JVM垃圾回收算法

原文地址:xeblog.cn/articles/23java

肯定可回收對象

引用計數法

給對象中添加一個引用計數器,每當有一個地方引用這個對象的時候,計數器的值就加1;當對象的引用失效時,計數器的值就減1;任什麼時候刻計數器爲0的對象就被斷定爲可回收的對象。
存在兩個對象之間互相循環引用的問題算法

Object obj1 = obj2
Object obj2 = obj1
複製代碼

對象 obj1 引用了對象 obj2 ,對象 obj2 又引用着對象 obj1,兩個對象互相引用,使得計數器都不能爲0,這種狀況若是使用 引用計數法 就沒法判斷對象是不是可回收的。spa

可達性分析算法

經過一系列的稱爲 GC Roots 的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲 引用鏈 ,當一個對象到 GC Roots 沒有任何 引用鏈 相連時,則證實此對象是可回收的。線程

如圖所示,對象 Object 五、Object 六、Object 7 雖然互相有關聯,可是它們到 GC Roots 是不可達的,因此它們將會被暫定爲是可回收的對象。但此時斷定並無徹底結束,由於斷定一個對象是不是可回收是須要通過兩次標記過程的,上述是第一次的標記過程,第二次標記則是將第一次標記的對象進行一次篩選:經過判斷該對象是否須要執行 finalize() 方法。若是該對象覆蓋了 finalize() 方法,而且系統沒有運行過該方法(finalize() 方法全局只運行一次),則表示該對象須要執行finalize() 方法,那麼這個對象將會被放入到一個叫 F-Queue 的隊列中,等待虛擬機中的一個低優先級的Finalizer 線程去執行它。在執行 finalize() 方法的過程當中,只要該對象沒有和 GC Roots 引用鏈上的任何一個對象有關聯,這個對象才能被真正的定爲是可回收的對象。指針

能夠做爲 GC Roots 的對象:code

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象;
  • 方法區中類靜態屬性引用的對象;
  • 方法區中常量引用的對象;
  • 本地方法棧中JNI(Native方法)引用的對象。

JVM就是採用 可達性分析算法 來判斷對象是不是可回收的。cdn

回收方法區

方法區處於JVM的永久代區域,且永久代的垃圾回收效率遠低於堆中(尤爲是在新生代中)的回收效率,對於這塊區域主要是回收兩部份內容:廢棄常量和無用類。對象

常量回收

回收常量與回收Java堆中的對象很是相似。若是當前系統中沒有任何一個變量與常量A相等,常量A也沒有在任何地方被引用,則常量A就是可回收的。blog

類回收

判斷一個類是否可回收是很是苛刻的,須要同時知足3個條件:隊列

  • 該類的全部實例都已經被回收,Java堆中不存在該類的任何實例;
  • 加載該類的 ClassLoader 已經被回收;
  • 該類對應的 java.lang.Class 對象沒有在任何地方被引用,沒法在任何地方經過反射訪問該類的方法。

垃圾回收算法

標記-清除算法

首先經過 可達性分析算法 標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象。

缺點

  • 標記和清除的效率都不高。
  • 標記清除後會產生大量不連續的內存碎片,空間碎片太多可能會致使程序在運行過程當中須要分配較大對象時,沒法找到足夠的連續內存而不得不提早觸發另外一次垃圾收集動做。

複製算法

將可用內存按容量分爲大小相等的兩塊,每次只使用其中的一塊,當這一塊內存用完時,就將還存活的對象複製到另一塊上,而後把已使用過的內存空間一次性清理掉。這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,簡單高效。

缺點

  • 將可用內存縮小爲原來的一半了。

優勢

  • 解決了內存碎片的問題。
  • 新生代中採用這種算法效率較高。

標記-整理算法

複製收集算法在對象存活率較高時就要進行較多的複製操做,效率將會變低,老年代通常不能直接選用這種算法。 根據老年代的特色,提出了一種「標記-整理」算法,標記過程與「標記-清除」算法同樣,不一樣的是這種算法不直接對可回收對象進行清理,而是讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。

缺點

  • 標記和整理的效率都不高。

優勢

  • 解決了內存碎片的問題。

分代回收算法

根據對象存活週期的不一樣,將 Java堆內存 劃分爲 新生代老年代,這樣能夠根據各個年代的特色採用最適當的回收算法。

新生代: 每次垃圾回收時都發現有大批對象死去,只有少許對象存活,可採用 複製算法,只須要付出少許存活對象的複製成本就能夠完成回收。

老年代: 對象存活率高,沒有額外空間對它進行分配擔保,必須使用 標記-清除標記-整理 算法進行回收。

參考

  • 《深刻理解Java虛擬機:JVM高級特性與最佳實踐 第二版》
相關文章
相關標籤/搜索