轉自 http://ju.outofmemory.cn/entry/74671
本文介紹的是Java里一個內建的概念,Finalizer。你可能對它對數家珍,但也可能從未聽聞過,這得看你有沒有花時間完整地看過一遍java.lang.Object類了。在java.lang.Object里面就有一個finalize()的方法。這個方法的實現是空的,不過一旦實現了這個方法,就會觸發JVM的內部行為,威力和危險並存。
如果JVM發現某個類實現了finalize()方法的話,那么見證奇跡的時刻到了。我們先來創建一個實現了這個非凡的finalize()方法的類,然后看下這種情況下JVM的處理會有什么不同。我們先從一個簡單的示例程序開始:
import java.util.concurrent.atomic.AtomicInteger; class Finalizable { static AtomicInteger aliveCount = new AtomicInteger(0); Finalizable() { aliveCount.incrementAndGet(); } @Override protected void finalize() throws Throwable { Finalizable.aliveCount.decrementAndGet(); } public static void main(String args[]) { for (int i = 0;; i++) { Finalizable f = new Finalizable(); if ((i % 100_000) == 0) { System.out.format("After creating %d objects, %d are still alive.%n", new Object[] {i, Finalizable.aliveCount.get() }); } } } }
這個程序使用了一個無限循環來創建對象。它同時還用了一個靜態變量aliveCount來跟蹤一共創建了多少個實例。每創建了一個新對象,計數器會加1,一旦GC完成后調用了finalize()方法,計數器會跟着減1。
你覺得這小段代碼的輸出結果會是怎樣的呢?由於新創建的對象很快就沒人引用了,它們馬上就可以被GC回收掉。因此你可能會認為這段程序可以不停的運行下去,:
After creating 345,000,000 objects, 0 are still alive. After creating 345,100,000 objects, 0 are still alive. After creating 345,200,000 objects, 0 are still alive. After creating 345,300,000 objects, 0 are still alive.
顯然結果並非如此。現實的結果完全不同,在我的Mac OS X的JDK 1.7.0_51上,程序大概在創建了120萬個對象后就拋出java.lang.OutOfMemoryError: GC overhead limitt exceeded異常退出了。
After creating 900,000 objects, 791,361 are still alive. After creating 1,000,000 objects, 875,624 are still alive. After creating 1,100,000 objects, 959,024 are still alive. After creating 1,200,000 objects, 1,040,909 are still alive. Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at java.lang.ref.Finalizer.register(Finalizer.java:90) at java.lang.Object.(Object.java:37) at eu.plumbr.demo.Finalizable.(Finalizable.java:8) at eu.plumbr.demo.Finalizable.main(Finalizable.java:19)
垃圾回收的行為
想弄清楚到底發生了什么,你得看下這段程序在運行時的狀況如何。我們來打開-XX:+PrintGCDetails選項再運行一次看看:
[GC [PSYoungGen: 16896K->2544K(19456K)] 16896K->16832K(62976K), 0.0857640 secs] [Times: user=0.22 sys=0.02, real=0.09 secs] [GC [PSYoungGen: 19440K->2560K(19456K)] 33728K->31392K(62976K), 0.0489700 secs] [Times: user=0.14 sys=0.01, real=0.05 secs] [GC-- [PSYoungGen: 19456K->19456K(19456K)] 48288K->62976K(62976K), 0.0601190 secs] [Times: user=0.16 sys=0.01, real=0.06 secs] [Full GC [PSYoungGen: 16896K->14845K(19456K)] [ParOldGen: 43182K->43363K(43520K)] 60078K->58209K(62976K) [PSPermGen: 2567K->2567K(21504K)], 0.4954480 secs] [Times: user=1.76 sys=0.01, real=0.50 secs] [Full GC [PSYoungGen: 16896K->16820K(19456K)] [ParOldGen: 43361K->43361K(43520K)] 60257K->60181K(62976K) [PSPermGen: 2567K->2567K(21504K)], 0.1379550 secs] [Times: user=0.47 sys=0.01, real=0.14 secs]