判斷對象是否已死分析總結——JVM系列(三)

寫在前面:2020年面試必備的Java後端進階面試題總結了一份複習指南在Github上,內容詳細,圖文並茂,有需要學習的朋友可以Star一下!
GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master

判斷對象是否已死

判斷對象是否已死就是找出哪些對象是已經死掉的,以後不會再用到的,就像地上有廢紙、飲料瓶和百元大鈔,掃地前要先判斷出地上廢紙和飲料瓶是垃圾,百元大鈔不是垃圾。判斷對象是否已死有引用計數算法和可達性分析算法。

1.引用計數算法

給每一個對象添加一個引用計數器,每當有一個地方引用它時,計數器值加 1;每當有一個地方不再引用它時,計數器值減 1,這樣只要計數器的值不爲 0,就說明還有地方引用它,它就不是無用的對象。如下圖,對象 2 有 1 個引用,它的引用計數器值爲 1,對象 1有兩個地方引用,它的引用計數器值爲 2 。

image

這種方法看起來非常簡單,但目前許多主流的虛擬機都沒有選用這種算法來管理內存,原因就是當某些對象之間互相引用時,無法判斷出這些對象是否已死,如下圖,對象 1 和對象 2 都沒有被堆外的變量引用,而是被對方互相引用,這時他們雖然沒有用處了,但是引用計數器的值仍然是 1,無法判斷他們是死對象,垃圾回收器也就無法回收。

image

2.可達性分析算法

瞭解可達性分析算法之前先了解一個概念——GC Roots,垃圾收集的起點,可以作爲 GC Roots 的有虛擬機棧中本地變量表中引用的對象、方法區中靜態屬性引用的對象、方法區中常量引用的對象、本地方法棧中 JNI(Native 方法)引用的對象。

當一個對象到 GC Roots 沒有任何引用鏈相連(GC Roots 到這個對象不可達)時,就說明此對象是不可用的,是死對象。

如下圖:object1、object2、object3、object4 和 GC Roots 之間有可達路徑,這些對象不會被回收,但 object5、object6、object7 到 GC Roots 之間沒有可達路徑,這些對象就被判了死刑。

image

上面被判了死刑的對象(object5、object6、object7)並不是必死無疑,還有挽救的餘地。進行可達性分析後對象和 GC Roots 之間沒有引用鏈相連時,對象將會被進行一次標記,接着會判斷如果對象沒有覆蓋 Object的finalize() 方法或者 finalize() 方法已經被虛擬機調用過,那麼它們就會被行刑(清除);如果對象覆蓋了 finalize() 方法且還沒有被調用,則會執行 finalize() 方法中的內容,所以在 finalize() 方法中如果重新與 GC Roots 引用鏈上的對象關聯就可以拯救自己,但是一般不建議這麼做,周志明老師也建議大家完全可以忘掉這個方法~

3.方法區回收

上面說的都是對堆內存中對象的判斷,方法區中主要回收的是廢棄的常量和無用的類。

判斷常量是否廢棄可以判斷是否有地方引用這個常量,如果沒有引用則爲廢棄的常量。

判斷類是否廢棄需要同時滿足如下條件:

  • 該類所有的實例已經被回收(堆中不存在任何該類的實例)。

  • 加載該類的 ClassLoader 已經被回收。

  • 該類對應的 java.lang.Class 對象在任何地方沒有被引用(無法通過反射訪問該類的方法)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章