System.gc()
在默認情況下,執(zhí)行System.gc()會顯示的觸發(fā)FullGC,同時對新生代以及老年大產(chǎn)生影響,進行回收。
其實在正常情況下,垃圾回收都是自動進行的,無需人為主動觸發(fā),因為頻繁的觸發(fā)垃圾回收對整體系統(tǒng)來說時沒有好處的,因此虛擬機會提供一個參數(shù)DisableExceptionGC來控制是否手工觸發(fā)GC的。
我們可以看以下具體的實現(xiàn):
Runtime.getRuntime().gc();
內(nèi)部是一個native方法:
public native void gc();
我們可以看下C++源碼:
可以看到,其實是通過判斷DisableExplicitGC這個參數(shù)去判斷是否進行垃圾回收的,所以我們可以i設(shè)置: -XX:-+DisableExplicitGC,條件判斷就無法成立,那么就會用顯示GC,使得System.gc等價于一個空函數(shù)調(diào)用。
同時,當我們使用System.gc的時候,如果垃圾回收器是CMS或者G1的話,默認是不會執(zhí)行并發(fā)的方式進行回收的,這時候我們需要打開虛擬機參數(shù):
-xx:+ExplicitGCInvokesConcurrent 該參數(shù),可以在使用CMS或者G1時,如果觸發(fā)system.gc,會并發(fā)的執(zhí)行垃圾回收。
finalize對于垃圾回收的影響
在java中提供了一個類似C++析構(gòu)函數(shù)的機制===finalize
protected void finalize() throws Throwable { }
可以看到,該方法設(shè)置成protected,可以用于子類重寫,用于在對象倍回收時進行資源的釋放。
在目前,普遍的認識是盡量不要使用finalize函數(shù)進行資源釋放,原因如下:
1.在finalize時可能會導(dǎo)致對象復(fù)活,在finalize函數(shù)執(zhí)行之前,可能在系統(tǒng)中對象的引用已經(jīng)倍清楚了,但是作為實例方法finalize,對象的this引用依然會被傳入方法內(nèi)部,如果引用外泄,對象就會復(fù)活,此時對象又會變成可觸及狀態(tài)。
2.finalize的執(zhí)行時間是不能保證的,完全由gc線程決定,因此極端情況下,若不發(fā)生gc,則將沒有己會執(zhí)行。推薦在try catch finally中釋放。
函數(shù)finalize是由FinalizerThread線程處理的,每一個即將被回收的并且包含有finalize方法的對象都會在正式回收前加入FinalizerThread的執(zhí)行隊列,該隊列是引用隊列,內(nèi)部實現(xiàn)為鏈表結(jié)構(gòu)。
Finalizer內(nèi)部封裝了實際的回收對象,referent字段則指向?qū)嶋H的對象引用。
由于對象在回收之前被Finalizer的referent字段進行強引用,并加入了FinalizerThread的執(zhí)行隊列,這意味著對象又變?yōu)榭蛇_性對象,因此阻止了對象的正?;厥?。
由于在引用對象中的元素排隊執(zhí)行finalize方法,一旦出現(xiàn)性能問題,將導(dǎo)致這些垃圾對象長時間堆積在內(nèi)存中,可能導(dǎo)致OOM異常。
部分取材自: 《實戰(zhàn)java虛擬機》
《深入理解jvm虛擬機》