2016-06-13 92 views
0

我的代碼基本上在Apache Spark上運行,其中每個容器都在單獨的JVM上運行。您爲容器指定了一定的內存限制。在我的程序中,一個容器完成了一項任務,但是當它試圖執行另一項任務時,它會崩潰,說超出了內存限制。如果我在單獨的容器中運行每個任務,它們總是運行良好。所以,看起來在任務完成後留下了一些未關閉的資源,我無法在代碼中找到它們,而這些未關閉的資源增加了容器的內存。所以,我的問題是,Java中有沒有辦法告訴JVM強制關閉所有資源。我也可以強制垃圾收集。我想在每項任務結束時執行這兩個步驟。強制關閉Java中所有未關閉的資源

+1

不,你真的需要小心你的程序來清理不必要的對象。 Java僅爲符合GC要求的對象釋放內存(但在拋出OutOfMemory錯誤之前它可靠地執行此操作)。 – Thilo

+1

您可以讓JVM在進入OOM時產生堆內存轉儲,以查看仍然存在的內容。有一個啓動標誌。 – Thilo

+0

您一般無法「關閉所有未關閉的資源」,因爲您的程序可能仍在使用這些資源。正如@Thilo所提到的,堆轉儲來分析任何實際的泄漏可能是您最好的選擇。 –

回答

2

您可以運行System.gc();但我懷疑這會幫助 - 內存不足時,將Java垃圾收集,只有失敗如果這需要太長時間。但是你描述它的方式,你可能沒有資源(=文件,套接字等)打開,但是大對象可達。確保返回的對象不會引用不必要的中間數據,也不會在static變量中存儲除常量之外的任何內容。

使用例如visualvm或其他任何可以產生堆轉儲的內容來查找哪些對象支持您的內存。

我知道Scala沒有這個功能。但Java 8具有自動閉合的外部資源,被稱爲嘗試 - 與資源一個很好的功能:離開這個塊時

try(AutoCloseable foo = openSomeResource()) { 
    doSomething(); 
} 

會自動調用foo.close();,無論怎樣(例如例外,返回)。如果遵循這種模式,很難將資源保持開放。但是這指的是Java中所謂的「資源」,它們必須實現AutoCloseable接口,您可能沒有打開資源,但可訪問對象。假設有很多關於如何調試Java/Scala內存泄漏的教程。但通常,第一步是獲得一個堆轉儲以查看正在使用多少內存。某些工具(例如hprof,內置的JVM)甚至可以使用行號顯示分配站點

+0

我想,大對象是在靜態變量中引用的,或者是從主要方法引用的地方。 – slartidan

+0

或在工作線程上的線程本地? – Det

+0

當方法返回時,應該調用main方法中的東西(除了可以從返回值中獲得的東西!),當線程完成時,線程本地人應該變爲不可達和GCable。我懷疑它只是返回值,保持對所有輸入數據的引用。 –

0

也許你可以使用try-與資源在JDK7以上

try (BufferedReader br = new BufferedReader(new FileReader(path))) { 
     return br.readLine(); 
     }