探究執(zhí)行System.gc()以及finalize對于垃圾回收的影響

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++源碼:

image

可以看到,其實是通過判斷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)。


image

Finalizer內(nèi)部封裝了實際的回收對象,referent字段則指向?qū)嶋H的對象引用。


image

由于對象在回收之前被Finalizer的referent字段進行強引用,并加入了FinalizerThread的執(zhí)行隊列,這意味著對象又變?yōu)榭蛇_性對象,因此阻止了對象的正?;厥?。

由于在引用對象中的元素排隊執(zhí)行finalize方法,一旦出現(xiàn)性能問題,將導(dǎo)致這些垃圾對象長時間堆積在內(nèi)存中,可能導(dǎo)致OOM異常。

image

部分取材自: 《實戰(zhàn)java虛擬機》
《深入理解jvm虛擬機》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容