jvm(4)---垃圾回收(哪些物件可以被回收)

白露非霜發表於2019-06-30

1.java堆中幾乎放著所有物件的例項,那麼什麼樣子的物件才是可以被回收的呢?

1.1.引用計數法:

給物件新增一個引用計數器,當有地方引用的時候,計數器就+1,引用失效就-1;任何時候當計數器為0,那麼這個物件就是可以被回收的。該方法實現簡單,效率也高,但是並沒有被主流的虛擬機器採用,因為很難解決物件互相迴圈引用問題。

1.2.可達性分析演算法

這個的基本思想就是通過一系列的“GC Roots”作為物件的起點,從這些節點開始向下搜尋,節點所走過的路徑稱為引用鏈,當一個物件到 GC Roots 沒有任何引用鏈相連的話,則證明此物件是不可用的。

那些可以作為GC Roots節點呢? 一般來說類載入器、Thread、虛擬機器棧的本地變數表、static成員、常量引用、本地方法棧的變數等等。

1.3 finalize()方法(只會被呼叫一次)

即使在可達性分析演算法中不可達的物件,也並非是“非死不可”的,這時候它們暫時處於“緩刑”階段,要真正宣告一個物件死亡,至少要經歷再次標記過程。

標記的前提是物件在進行可達性分析後發現沒有與GC Roots相連線的引用鏈。

1.3.1. 第一次標記並進行一次篩選。

篩選的條件是此物件是否有必要執行finalize()方法。

當物件沒有覆蓋finalize方法,或者finzlize方法已經被虛擬機器呼叫過,虛擬機器將這兩種情況都視為“沒有必要執行”,物件被回收。

1.3.2. 第二次標記

如果這個物件被判定為有必要執行finalize()方法,那麼這個物件將會被放置在一個名為:F-Queue的佇列之中,並在稍後由一條虛擬機器自動建立的、低優先順序的Finalizer執行緒去執行。這裡所謂的“執行”是指虛擬機器會觸發這個方法,但並不承諾會等待它執行結束。這樣做的原因是,如果一個物件finalize()方法中執行緩慢,或者發生死迴圈(更極端的情況),將很可能會導致F-Queue佇列中的其他物件永久處於等待狀態,甚至導致整個記憶體回收系統崩潰。

finalize()方法是物件脫逃死亡命運的最後一次機會,稍後GC將對F-Queue中的物件進行第二次小規模標記,如果物件要在finalize()中成功拯救自己----只要重新與引用鏈上的任何的一個物件建立關聯即可,譬如把自己賦值給某個類變數或物件的成員變數,那在第二次標記時它將移除出“即將回收”的集合。如果物件這時候還沒逃脫,那基本上它就真的被回收了。

1.4 如何判斷一個常量是廢棄常量

假如在常量池中存在字串 "abc",如果當前沒有任何String物件引用該字串常量的話,就說明常量 "abc" 就是廢棄常量,如果這時發生記憶體回收的話而且有必要的話,"abc" 就會被系統清理出常量池。

1.5 如何判斷一個類是無用的類

1.該類所有的例項都已經被回收,也就是 Java 堆中不存在該類的任何例項。

2.載入該類的 ClassLoader 已經被回收。

3.該類對應的 java.lang.Class 物件沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

但是並不是和物件一樣不使用了就會必然被回收。

 

相關文章