1 引用計數算法
1.1 算法思想
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;
當引用失效時,計數器值就減1;
任何時候計數器為0時的對象就是不能再被使用。
1.2 特點
- 優點:實現簡單;判定效率高。
- 缺點:很難解決對象之間相互循環引用的問題。(所以虛擬機不是通過引用計數算法判斷對象是否存活)
2 可達性分析算法
2.1 算法思想
通過一系列稱為GC Roots 的對象作為起始點,從這些節點開始向下搜索,搜索走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連的時候,則證明此對象是不可用的。
2.2 GC Roots的對象
- 虛擬機棧(棧幀中本地變量表)中引用的對象;
- 方法區中類靜態屬性引用的對象;
- 方法區中常量引用的對象;
- 本地方法棧中JNI(Native方法)引用的對象;
3 對象存亡判斷
3.1 兩次標記過程
真正宣布一個對象已死,必須經歷兩次標記過程:
- 如果對象在進行可達性分析后發現沒有與GC Roots相連接的引用鏈,則將會被第一次標記並且進行一次篩選;
- 若這個對象被判定有必要執行
finalize()
方法,則該對象放置在一個叫F-Queue
隊列中,並之后由VM自動建立的、低優先級的Finalizer線程去執行它。 - finalize()方法是對象逃脫死亡的最后一次機會,稍后GC將對F-Queue隊列中的對象進行第二次小規模的標記,若finalize()能夠救活自己,則第二次標記時,將被移除出“即將回收”的集合;若對象沒有完成自救,則回收。
3.2 補充
- 篩選的條件:這個對象有沒有必要去執行finalize()方法?當對象沒有覆蓋finalize()方法或者finalize()方法已經被VM掉用過,則“沒有必要執行“
- “執行”操作的觸發:是VM會觸發這個方法,而不承諾等它運行結束,原因:如果一個對象在finalize()方法中執行緩慢,或發生死循環,將導致F-Queue隊列中其他對象永遠處於等待,甚至導致整個內存回收系統崩潰。
- finalize()中對象自救:只要重新與引用鏈上的任何一個對象建立關聯即可,譬如把自己(this關鍵字)賦值給某個類變量或者對象的成員變量。finalize()最多只會被系統自動調用一次,所以自救機會只有一次。finalize()方法的運行代價搞,不確定大,無法保證各個對象的調用順序。