【JVM】 垃圾回收算法

簡介:對JVM常見的垃圾回收算法做個整理

引用計數器算法(Reference Counting)

給每一個對象設置一個引用計數器,每當有一個地方引用這個對象的時候,計數器就加 1,每當引用失效的時候就減 1。垃圾回收時,只用收集計數爲0的對象。
缺點:無法處理循環引用的問題。如父對象有一個對子對象的引用,子對象反過來引用父對象。這樣,他們的引用計數永遠不可能爲0

複製算法(Copying)

複製算法是將內存空間分爲大小相同的兩個區域,每次只使用其中一個區域,當這一區域使用完了,就把當前存活的對象複製到另一區域,然後一次性清空當前區域。
缺點:只能利用一半的內存空間。

標記-清除算法(Mark-Sweep)

此算法執行分兩階段,第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。
缺點:此算法需要暫停整個應用,同時,會產生內存碎片。

標記-整理算法(Mark-Compact)

此算法結合了“標記-清除”和“複製”兩個算法的優點。分爲兩個階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,清除未標記的對象並且把存活對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-清除”的碎片問題,同時也避免了“複製”算法的空間問題。

可達性分析算法

通過一些列的“GC Roots”對象作爲起始點,從這些對象開始往下搜索,搜索所經過的路徑稱之爲“引用鏈”。當一個對象到 GC Roots 沒有任何引用鏈相連的時候,證明此對象是可以被回收的。

分代收集算法

分代收集算法是目前大部分JVM的垃圾收集器採用的算法。它的核心思想是根據對象存活的生命週期將內存劃分爲若干個不同的區域。一般情況下將堆區劃分爲老年代(Tenured Generation)和新生代(Young Generation),在堆區之外還有一個代就是永久代(Permanet Generation)。老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那麼就可以根據不同代的特點採取最適合的收集算法。

新生代(Young Generation)的回收算法
a) 所有新生成的對象首先都是放在新生代的。新生代的目標就是儘可能快速的收集掉那些生命週期短的對象。

b) 新生代內存按照8:1:1的比例分爲一個eden區和兩個survivor(survivor0,survivor1)區。大部分對象在eden區中生成。回收時先將eden區存活對象複製到一個survivor0區,然後清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活對象複製到另一個survivor1區,然後清空eden和這個survivor0區,此時survivor0區是空的,然後將survivor0區和survivor1區交換,即保持survivor1區爲空, 如此往復。

c) 當survivor1區不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收。

d) 新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)。

老年代(Old Generation)的回收算法
a) 在新生代中經歷了N次垃圾回收後仍然存活的對象,就會被放到老年代中。因此,可以認爲老年代中存放的都是一些生命週期較長的對象。

b) 老年代的內存比新生代也大很多(大概比例是1:2),當老年代內存滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代對象存活時間比較長,存活率標記高。

持久代(Permanent Generation)的回收算法
  用於存放靜態文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者調用一些class,例如Hibernate 等,在這種時候需要設置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代也稱方法區。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章