JVM之GC算法

1、什麼是GC

JVM GC是:JVM的垃圾回收算法,如今的JVM基本採用分代收集,Young區收集頻繁,Old區收集較少,Perm(永久代)基本不回收;JVM進行GC時大部分是對新生代的回收,少許的全局回收。html

GC按照做用的區域分爲:算法

Minor GC:做用於新生代數據結構

Major GC(Full GC):做用於老年代,偶爾也會回收老年代和永久代。spa

2、如何定位垃圾

一、引用計數法線程

 引用計數算法很簡單,它其實是經過在對象頭中分配一個空間來保存該對象被引用的次數。若是該對象被其它對象引用,則它的引用計數加一,若是刪除對該對象的引用,那麼它的引用計數就減一,當該對象的引用計數爲0時,那麼該對象就會被標記爲垃圾對象。指針

第10行 str引用了「ABC」 則「ABC」的計算器等於1。第11行str釋放了該引用,因此「ABC」的計數器就減一。
優勢:實現簡單,斷定高效,能夠很好解決大部分場景的問題。
缺點:orm

  • 很難解決對象之間相互循環引用的問題,當兩個對象再也不被訪問時,由於相互引用對方,致使引用計數不爲0;
  • 開銷較大,頻繁且大量的引用變化,帶來大量的額外運算;主流的JVM都沒有選用引用計數算法來管理內存;

二、可達性分析法(根搜索算法)htm

可達性分析法:經過一系列"GC Roots"對象做爲起始點,開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,認爲該對象不可達,則證實該對象是不可用的;
優勢:對象

  • 更加精確和嚴謹,能夠分析出循環數據結構相互引用的狀況;
  • 主流的調用程序語言(Java、C#等)在主流的實現中,都是經過可達性分析來斷定對象是否存活的。

缺點:blog

  • 實現比較複雜;
  • 須要分析大量數據,消耗大量時間;
  • 分析過程須要GC停頓(引用關係不能發生變化),即停頓全部Java執行線程(稱爲"Stop The World",是垃圾回收重點關注的問題);

哪些對象能夠做爲GC ROOT對象(GCRoot 能夠是一個也能夠是多個):

  • 一、虛擬機棧(棧楨中的局部變量區,也叫局部變量表)中引用的變量
  • 二、方法區中類的靜態屬性引用的對象
  • 三、方法區中常量引用的對象
  • 四、本地方法棧中JNI(Native)引用的對象

 3、垃圾回收算法

一、標記-複製:它將可用內存容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊用完以後,就將還存活的對象複製到另一塊上面,而後在把已使用過的內存空間一次理掉。

JVM實現原理:Survivor區,一塊叫From,一塊叫To,對象存在Eden和From塊。當進行GC時,Eden存活的對象全移到To塊,而From中,存活的對象按年齡值肯定去向,當達到必定值(年齡閾值,經過-XX:MaxTenuringThreshold可設置,默認=15)的對象會移到年老代中,沒有達到值的複製到To區,而後直接清空Eden和From。以後,From和To交換角色,新的From即爲原來的To塊,新的To塊即爲原來的From塊,且新的Form塊中對象年齡加1.
優勢:內存分配時也不用考慮內存碎片等問題;實現簡單,運行高效;能夠利用指針碰撞(bump-the-pointer)實現快速內存分配
缺點:

  • 空間浪費:可用內存縮減爲原來的一半,太過浪費(解決:能夠改良,不按1:1比例劃分);
  • 效率隨對象存活率升高而變低:當對象存活率較高時,須要進行較多複製操做(對象的引用地址須要複製),效率將會變低,因此該算法不適合對象存活率較高的場景或者區域。

應用場景:

  • 如今商業JVM都採用這種算法(經過改良缺點1)來回收新生代;
  • 如Serial收集器、ParNew收集器、Parallel Scavenge收集器、G1(從局部看)。

二、標記-清除:首先標記出須要回收的對象,標記完成以後統一清除對象。

標記:從根集合開始掃描,標記存貨的對象
清除:掃描整個堆內存空間,回收未被標記的對象,使用free-list記錄可使用的區域

優勢:基於最基礎的可達性分析算法,它是最基礎的收集算法;然後續的收集算法都是基於這種思路並對其不足進行改進獲得的;
缺點:

  • 效率問題:標記和清除都須要掃描,兩個過程的效率都不高;
  • 空間問題:標記清除後會產生大量不連續的內存碎片,這會致使分配大內存對象時,沒法找到足夠的連續內存,從而須要提早觸發另外一次垃圾收集動做。
  • stop-the-Word:在標記時須要暫停JVM用戶進程

應用場景:針對老年代

三、標記-整理

 

標記-整理:標記操做和「標記-清理」算法一致,後續操做不僅是直接清理對象,而是在清理無用對象前,先將存活的對象都向一端移動,並更新引用其對象的指針,而後直接清理掉端邊界之外的內存。

標記:和「標記-清理」算法一致

整理:掃描整個堆內存空間,將存活的對象都向一端移動,並更新引用其對象的指針,而後直接清理掉邊界之外的內存。整理的目的就是整合零散分佈的空間碎片爲一個連續的空間。

優勢:

  • 不會像複製算法,效率隨對象存活率升高而變低
  • 不會像標記-清除算法,產生內存碎片,由於清除前,進行了整理,存活對象都集中到空間一側;

缺點:主要是效率問題:除像標記-清除算法的標記過程外,還多了須要整理的過程,效率更低;
應用場景:回收老年代;
四、標記-清除-整理(Mark-Sweep-Compact)
  該算法是標記清除和標記整理的結合,標記-清除會產生碎片,標記-整理每次都進行整理效率不高;標記-清楚-整理 是若是老年代內存中沒有一塊連續續的空間能夠存放將要進入對象,就進行整理;若是內存中的空間能夠存放將要進入的對象,就進行標記-清除,這樣就節省了整理的步驟能夠提升效率。總結一句話:不是全部的時候都須要整理的,由於整理也付出代價。主要應用於老年代

總結: 沒有最好的算法,只有最合適的引用場景

 

 

 下一節:GC算法的實現

相關文章
相關標籤/搜索