2011-10-24 66 views
11

PS:我知道如何正確清理,而不依賴於finalize()JVM/GC是否在程序/線程退出時調用`finalize()`?

Java不能保證程序退出時,垃圾回收會被正確執行嗎?

E.g.可以說我已經將一些數據保存在緩存中,而不是頻繁地序列化,我還實現了finalize(),希望如果由於任何原因(崩潰除外),我的程序將優雅地退出,那麼緩存將寫入DB /文件/某些我的代碼在finalize()方法中存儲。但根據以下的小實驗,似乎JVM並沒有「優雅地」清理內存,它只是退出。

Java spec(見程序退出)什麼都不說ABT內存/ GC是如何退出處理。或者我應該看看規範的不同部分?

採取使用1.6.0.27 64位下面的例子中(在端輸出),在Windows 7

public class Main { 

     // just so GC might feel there is something to free.. 
    private int[] intarr = new int[10000]; 

    public static void main(String[] args) { 
     System.out.println("entry"); 
     Main m = new Main(); 
     m.foo(); 
     m = new Main(); 
     // System.gc(); 
     m.foo(); 
     m = null; 
     // System.gc(); 
     System.out.println("before System.exit(0);"); 
     System.exit(0); 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("finalize()"); 
     super.finalize(); 
    } 

    public void foo() { System.out.println("foo()"); } 
} 

/* 
* Prints: 
* entry 
* foo() 
* foo() 
* before System.exit(0); 
*/ 

變化:

  • 如果我去掉任一項System.gc()則沒有finalize()被稱爲。
  • 如果我取消兩個System.gc()的註釋,則finalize()被調用兩次。
  • 無論System.exit()被稱爲與否對finalize()是否被稱爲沒有任何影響。
+0

你的問題是程序可能在任何時候都不正常地死去。您可能還需要能夠在重新啓動時進行清理。 –

回答

10

沒有,Java不保證在程序退出的GC將觸發。如果您想在退出時使用Runtime.addShutdownHook方法進行操作。閱讀this Sun撰寫的關於SPEC說的文章。

Java平臺的規範對於 垃圾收集的實際工作原理做出了很少的承諾。以下是Java Virtual 機器規範(JVMS)關於內存管理的內容。

堆是在虛擬機啓動時創建的。堆存儲爲 對象由自動存儲管理系統(作爲垃圾收集器知道 )回收;對象從不顯式釋放。 Java虛擬機不採用特定類型的自動存儲管理系統,根據實現者的系統需求可以選擇存儲管理技術 。雖然看起來 令人困惑,但垃圾收集模型並非嚴格定義的實際上非常重要且有用 - 一個嚴格定義的垃圾收集模型可能不可能在所有平臺上實現。 同樣,它可能會妨礙有用的優化,並長期損害平臺的性能。

雖然沒有包含的 所需的垃圾收集器的行爲的完整定義,許多GC模型是 隱含通過一些在Java語言規範 和JVMS部分沒有指定任何一個地方。雖然沒有關於確切的 過程的保證,但所有符合標準的虛擬機都共享本章中描述的基本的對象生命週期。

+0

它(例如規格)在任何地方都這麼說嗎? – Kashyap

+1

雖然您提供的描述仍然沒有真正說明GC在退出時沒有完成,但我認爲已經充分表明它留給了JVMs impls ..感謝信息abt'addShutdownHooks()',不知道這一點。 – Kashyap

+1

在規範中沒有否定「GC不一定在退出時運行」的負面聲明。規範中的故意模棱兩可和我引用的廣泛陳述都是陳述的。 –

3

請參閱Runtime.runFinalizersOnExit()。請注意,它已被棄用,並注意其餘的評論。我認爲你可以合理地推斷它是默認關閉的,但你也應該注意它可以打開。

相關問題