《算法撕裂者》04 - 垃圾收集算法詳解

五、垃圾收集(GC)算法

最近在學習 JVM 的知識,作爲一個 Java 開發人員不懂 JVM 實在是不應該,畢竟底層基礎決定上層建築,而作爲 JVM 裏面的重點之一必然是垃圾收集(GC)了,那今天就帶大家一起來了解下這是辣雞,竟然如此的出名。(這篇也還是放在《算法撕裂者》系列吧,畢竟帶"算法"兩字,就水一波吧)

0、java對象內存申請過程

img

  1. JVM會試圖爲相關Java對象在Eden中初始化一塊內存區域;當Eden空間足夠時,內存申請結束。否則到下一步;
  2. JVM試圖釋放在Eden中所有不活躍的對象(minor collection),釋放後若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區;
  3. Survivor區被用來作爲Eden及old的中間交換區域,當old區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區;
  4. 當old區空間不夠時,JVM會在old區進行major collection;
  5. 垃圾收集後,若Survivor及old區仍然無法存放從Eden複製過來的部分對象,導致JVM無法在Eden區爲新對象創建內存區域,則出現"Out of memory錯誤";

1、stop the world

在新生代進行的GC叫做minor GC,在老年代進行的GC都叫major GC,Full GC同時作用於新生代和老年代。在垃圾回收過程中經常涉及到對對象的挪動(比如上文提到的對象在Survivor 0和Survivor 1之間的複製),進而導致需要對對象引用進行更新。爲了保證引用更新的正確性,Java將暫停所有其他的線程,這種情況被稱爲“Stop-The-World”,導致系統全局停頓。Stop-The-World對系統性能存在影響,因此垃圾回收的一個原則是儘量減少“Stop-The-World”的時間。

不同垃圾收集器的Stop-The-World情況,Serial、Parallel和CMS收集器均存在不同程度的Stop-The-Word情況;而即便是最新的G1收集器也不例外。

  • Java 中一種全局暫停的現象,JVM掛起狀態
  • 全局停頓,所有Java代碼停止,native代碼可以執行,但不能與JVM交互
  • 多半由於JVM的GC引用,如:
    • 老年代空間不足
    • 永生代(jkd7)或者元數據空間(jkd8)不足。
    • System.gc()方法調用。
    • CMS GC時出現promotion failed和concurrent mode failure
    • YoungGC時晉升老年代的內存平均值大於老年代剩餘空間
    • 有連續的大對象需要分配
  • 除了GC還有以下原因:
    • 死鎖檢查
    • Dump線程–人爲因素
    • 堆Dump–人爲因素

關於stop the world 可查看: https://www.jianshu.com/p/d686e108d15f

2、如何判斷對象是否“死去”?

在堆裏面存放着Java中幾乎所有的對象實例,垃圾收集器在對堆進行回收之前,第一件事情就是要確定哪些對象還存活着,哪些對象已經死去(即不可能在被任何途徑使用的對象)。

  • 引用計數算法
  • 可達性分析算法
a、引用計數算法

引用計數法顧名思義,就是對一個對象被引用的次數進行計數,當增加一個引用計數就加1,減少一個引用計數就減1。

image

圖片來自 https://www.cnblogs.com/leefreeman/p/7389919.html

上圖表示3個Teacher的引用指向堆中的Teacher對象,那麼Teacher對象的引用計數就是3,以此類推Student對象的引用計數就是2。

image

上圖表示Teacher對象的引用減少爲2,Student對象的引用減少爲0(減少的原因是該引用指向了null,例如teacher3=null),按照引用計數算法,Student對象的內存空間將被回收掉。

引用計數算法原理非常簡單,是最原始的回收算法,但是java中沒有使用這種算法,原因有2:

  1. 頻繁的計數影響性能,

  2. 它無法處理【循環引用】的問題。

    例如Teacher對象中引用了Student對象,Student對象中又引用了Teacher對象,這種情況下,對象將永遠無法被回收。

b、可達性分析算法

這個算法的基本思想就是,通過一系列稱爲 “GC Roots” 的對象作爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲【引用鏈】(Reference Chain),當一個對象到 GC Roots 沒有任何引用鏈相連(用圖論的話來說,就是從 GC Roots 到這個對象不可達)時,則證明此對象時不可用的。

1.jpg-40.4kB

在 Java 語言中,可作爲 GC Roots 的對象包括一下幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象
  • 方法區中靜態屬性引用的對象
  • 方法區中常量引用的對象
  • 本地方法棧中 JNI (即一般說是 Native 方法)引用的對象
c、再談引用

在 JDK 1.2 之後,Java 對引用的概念進行了擴充,將引用分爲

  1. 強引用(Strong Reference)
  2. 軟引用(Soft Reference)
  3. 弱引用(Weak Reference)
  4. 虛引用(Phantom Reference)
  • 強引用

    代碼中普遍存在的,類似 “ Object obj = new Object() ” 這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。

  • 軟引用

    用來描述一些還有用但非必須的對象。軟引用所關聯的對象,在系統將要發生內存溢出異常之前,將會把這些對象列入回收範圍,並進行二次回收。如果這次回收還沒有足夠的內存,纔會拋出內存溢出異常。提供了 SoftReference 類實現軟引用。

  • 弱引用

    描述非必須的對象。強度比軟引用更弱一些,被弱引用關聯的對象,只能**生存到下一次垃圾收集發生之前。**當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。提供了 WeakReference類實現弱引用。

  • 虛引用

    一個對象是否有虛引用,完全不會對其生存時間構成影響,也無法通過一個虛引用來取得一個對象實例。爲一個對象設置虛引用關聯的唯一目的,就是能在這個對象被收集器回收時收到一個系統通知。通過了 PhantomReference 類實現虛引用。

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

什麼是標記-清除算法

分爲【標記】和【清除】兩個階段。首先標記處所有需要回收的對象,在標記完成後統一回收被標記的對象。

有什麼缺點?
  1. 效率問題:標記和清除的效率都不高
  2. 空間問題:標記清除後會產生大量**【不連續的內存碎片】,空間碎片太多可能導致,程序分配較大對象**時無法找到足夠的連續內存,不得不提前出發另一次垃圾收集動作。

2.jpg-81.6kB

4、複製算法(Copying)- 新生代

將可用內存按容量劃分爲【大小相等的兩塊】,每次只使用其中一塊。當這一塊的內存用完了,就將存活着的對象複製到另一塊上面,然後再把已經使用過的內存空間一次清理掉。

優點?

複製算法使得每次都是針對其中的一塊進行內存回收,內存分配時也不用考慮內存碎片等複雜情況,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。

缺點?

將內存縮小爲原來的一半。在對象存活率較高時,需要執行較多的【複製操作】,效率會變低。

3.jpg-95.7kB

應用?

商業的虛擬機都採用複製算法來回收新生代。因爲新生代中的對象容易死亡,所以並不需要按照1:1的比例劃分內存空間,而是將內存分爲一塊較大的 Eden 空間兩塊較小的 Survivor 空間。每次使用 Eden 和其中的一塊 Survivor。

當回收時,將 Eden 和 Survivor 中還存活的對象一次性拷貝到另外一塊 Survivor 空間上,最後清理掉 Eden 和剛纔用過的 Survivor 空間。**Hotspot 虛擬機默認 Eden 和 Survivor 的大小比例是8:1,**也就是每次新生代中可用內存空間爲整個新生代容量的90%(80% + 10%),只有10%的內存是會被“浪費”的。

5、標記-整理算法(Mark-Compact)- 老年代

標記過程仍然與“標記-清除”算法一樣,但不是直接對可回收對象進行清理,而是讓所有存活的對象向一端移動,然後直接清理掉邊界以外的內存。

img

優點?

經過整理(壓縮),即再次掃描,並往一端**【滑動】**存活對象,沒有內存碎片

缺點?

需要移動對象的成本

6、分代收集算法

根據對象的存活週期,將內存分爲幾塊。一般是把【Java堆】分爲【新生代】和【老年代】, 這樣就可以根據各個年代的特點,採用最適當的收集算法。

  • 新生代:每次垃圾收集時會有大批對象死去,只有少量存活,所以選擇【複製算法】,只需要少量存活對象的複製成本就可以完成收集。
  • 老年代:對象存活率較高,沒有額外空間對它進行分配擔保,必須使用【標記-清除】或【標記-整理】算法進行收集。

參考資料:

《深入理解Java虛擬機(第2版)》 周志明

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