天天看點

深入剖析GC 算法-(垃圾回收系列:3)

作者:JAVA後端架構
深入剖析GC 算法-(垃圾回收系列:3)

相關術語翻譯說明:

Mark,标記;

Sweep,清除;

Compact,整理; 也有人翻譯為壓縮,譯者認為GC時不存在壓縮這回事。

Copy,複制; copy 用作名詞時一般翻譯為拷貝/副本,用作動詞時翻譯為複制。

注: 《垃圾回收算法手冊》将 Mark and Sweep 翻譯為: 标記-清掃算法; 譯者認為 标記-清除 更容易了解。

本章簡要介紹GC的基本原理和相關技術, 下一章節再詳細講解GC算法的具體實作。各種垃圾收集器的實作細節雖然并不相同,但總體而言,垃圾收集器都專注于兩件事情:

  • 查找所有存活對象
  • 抛棄其他的部分,即死對象,不再使用的對象。

第一步, 記錄(census)所有的存活對象, 在垃圾收集中有一個叫做 标記(Marking) 的過程專門幹這件事。

标記可達對象(Marking Reachable Objects)

現代JVM中所有的GC算法,第一步都是找出所有存活的對象。下面的示意圖對此做了最好的诠釋:

深入剖析GC 算法-(垃圾回收系列:3)

首先,有一些特定的對象被指定為 Garbage Collection Roots(GC根元素)。包括:

  • 目前正在執行的方法裡的局部變量和輸入參數
  • 活動線程(Active threads)
  • 記憶體中所有類的靜态字段(static field)
  • JNI引用

其次, GC周遊(traverses)記憶體中整體的對象關系圖(object graph),從GC根元素開始掃描, 到直接引用,以及其他對象(通過對象的屬性域)。所有GC通路到的對象都被标記(marked)為存活對象。

存活對象在上圖中用藍色表示。标記階段完成後, 所有存活對象都被标記了。而其他對象(上圖中灰色的資料結構)就是從GC根元素不可達的, 也就是說程式不能再使用這些不可達的對象(unreachable object)。這樣的對象被認為是垃圾, GC會在接下來的階段中清除他們。

在标記階段有幾個需要注意的點:

在标記階段,需要暫停所有應用線程, 以周遊所有對象的引用關系。因為不暫停就沒法跟蹤一直在變化的引用關系圖。這種情景叫做 Stop The World pause (全線停頓),而可以安全地暫停線程的點叫做安全點(safe point), 然後, JVM就可以專心執行清理工作。安全點可能有多種因素觸發, 目前, GC是觸發安全點最常見的原因。

此階段暫停的時間, 與堆記憶體大小,對象的總數沒有直接關系, 而是由存活對象(alive objects)的數量來決定。是以增加堆記憶體的大小并不會直接影響标記階段占用的時間。

标記 階段完成後, GC進行下一步操作, 删除不可達對象。

删除不可達對象(Removing Unused Objects)

各種GC算法在删除不可達對象時略有不同, 但總體可分為三類: 清除(sweeping)、整理(compacting)和複制(copying)。下一章節将詳細講解這些算法。

Sweep(清除)

Mark and Sweep(标記-清除) 算法的概念非常簡單: 直接忽略所有的垃圾。也就是說在标記階段完成後, 所有不可達對象占用的記憶體空間, 都被認為是空閑的, 是以可以用來配置設定新對象。

這種算法需要使用 空閑表(free-list),來記錄所有的空閑區域, 以及每個區域的大小。維護空閑表增加了對象配置設定時的開銷。此外還存在另一個弱點 —— 明明還有很多空閑記憶體, 卻可能沒有一個區域的大小能夠存放需要配置設定的對象, 進而導緻配置設定失敗(在Java 中就是 OutOfMemoryError)。

深入剖析GC 算法-(垃圾回收系列:3)

Compact(整理)

标記-清除-整理算法(Mark-Sweep-Compact), 将所有被标記的對象(存活對象), 遷移到記憶體空間的起始處, 消除了标記-清除算法的缺點。 相應的缺點就是GC暫停時間會增加, 因為需要将所有對象複制到另一個地方, 然後修改指向這些對象的引用。此算法的優勢也很明顯, 碎片整理之後, 配置設定新對象就很簡單, 隻需要通過指針碰撞(pointer bumping)即可。使用這種算法, 記憶體空間剩餘的容量一直是清楚的, 不會再導緻記憶體碎片問題。

深入剖析GC 算法-(垃圾回收系列:3)

Copy(複制)

标記-複制算法(Mark and Copy) 和 标記-整理算法(Mark and Compact) 十分相似: 兩者都會移動所有存活的對象。差別在于, 标記-複制算法是将記憶體移動到另外一個空間: 存活區。标記-複制方法的優點在于: 标記和複制可以同時進行。缺點則是需要一個額外的記憶體區間, 來存放所有的存活對象。

深入剖析GC 算法-(垃圾回收系列:3)

為幫助開發者們提升面試技能、有機會入職BATJ等大廠公司,特别制作了這個專輯——這一次整體放出。

大緻内容包括了: Java 集合、JVM、多線程、并發程式設計、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大廠面試題等、等技術棧!

深入剖析GC 算法-(垃圾回收系列:3)

歡迎大家關注公衆号【Java爛豬皮】,回複【666】,擷取以上最新Java後端架構VIP學習資料以及視訊學習教程,然後一起學習,一文在手,面試我有。

每一個專欄都是大家非常關心,和非常有價值的話題,如果我的文章對你有所幫助,還請幫忙點贊、好評、轉發一下,你的支援會激勵我輸出更高品質的文章,非常感謝!

深入剖析GC 算法-(垃圾回收系列:3)

繼續閱讀