1. 程式人生 > 程式設計 >JVM核心知識-GC機制

JVM核心知識-GC機制

Java開發相對於C語言最方便的點,就是程式碼上不需要主動去管理記憶體的回收,而由JVM負責分配回收。

GC演演算法

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

標記出所有需要回收的記憶體物件,當垃圾回收時只清除標記的物件。缺點:回收的空間不連續,可能導致建立物件雖然未使用空間足夠,但連續的空間不足無法建立。

標記複製演演算法(Mark-Copy)

將空間分為A、B兩塊。物件在A塊建立。當A空間滿了,垃圾回收,將A中存活的物件複製到B中,清空A空間。之後在B空間中盡享相同的邏輯。優點:合理規劃了空間的連續性,每次回收都是整塊記憶體的回收。缺點:將記憶體分為了兩塊,每次只能用一半的記憶體。

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

結合標記清除和標記複製的缺點,為了優化演演算法。提出了標記整理演演算法。物件的回收依然使用標記方式,在垃圾回收時,把存活的物件整理到記憶體一端,將其他記憶體回收。這樣做的的好處時騰出了一整塊連續的空間。優點:創造了連續的空間環境缺點:效率有所損失

分代收集演演算法(Generational Collection)

根據物件的存活特性,將記憶體分為幾個區域,分別對不同區域進行不同的回收演演算法。目前大部分的JVM都採用分代收集演演算法。常見的將堆分為年輕代、老年代,以及堆外的永久代。老年代存放的物件一般回收較少,年輕代回收的物件相對更多。一般物件多數是”朝生夕死“,即建立完很快就會被回收。針對這些區域的物件特性採用不同的收集演演算法,提高記憶體利用率。例如:以hotspot為例,記憶體劃分為年輕代、老年代、永久代,年輕代又分為Eden、From Survivor、To Survivorimage.png

年輕代採用標記複製演演算法,物件的建立在Eden區進行,當Eden區進行垃圾回收時,將Eden存活物件複製到From Survivor區,清空Eden。當From Survivor也滿了,將Eden區和From Survivor存活的物件複製到To Survivor區,清空Eden和From Survivor。老年代採用標記整理演演算法,將存活的物件整理到一端,騰出連續的空間。

GC收集器

Serial/Serial Old收集器

Serial收集器是單執行緒收集器,是分代收集器。年輕代使用單執行緒複製收集演演算法(Serial收集器),老年代使用單執行緒標記整理演演算法(Serial Old收集器)。進行垃圾收集時,必須暫停其他所有的工作執行緒,直到它收集結束(Stop TheWorld)。引數:-XX:UseSerialGC特點:單執行緒沒有多執行緒切換的開銷。

ParNew 收集器

相當於Serial收集器的多執行緒版本。年輕代使用並行複製收集演演算法(ParNew 收集器),老年代使用單執行緒標記整理演演算法(Serial Old收集器)。引數:-XX:+UseConcMarkSweepGC":指定使用CMS後,會預設使用ParNew作為新生代收集器;-XX:+UseParNewGC":強制指定使用ParNew;-XX:ParallelGCThreads":指定垃圾收集的執行緒數量,ParNew預設開啟的收集執行緒與CPU的數量相同;特點:ParNew收集器在單CPU環境中不比Serial效果好,甚至可能更差,兩個CPU也不一定跑的過,但隨著CPU數量的增加,效能會逐步增加。

Parallel Scavenge/Parallel Old收集器

JDK8預設收集器。同樣是併發收集器,Parallel Scavenge收集器的關注點與其他收集器不同, Parallel Scavenge收集器的目標則是達到一個可控制的吞吐量(Throughput)(吞吐量=執行使用者程式碼時間/(執行使用者程式碼時間+垃圾收集時間))Parallel Old是Parallel老年代收集器,使用標記整理演演算法。jdk1.6之前老年代只能使用Serial Old收集器。引數:

  • -XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間
  • -XX:GCTimeRatio:設定吞吐量大小
  • -XX:+UseAdaptiveSizePolicy:GC自適應的調節策略(GC Ergonomics),當這個引數開啟之後,無需手動指定年輕代空間大小,也不需要設定Survivor物件年齡,虛擬機器器會根據執行情況,動態調整這些引數值。
    特點:能夠控制GC的吞吐量,自適應調整。

CMS 收集器(ConcurrentMarkSweep)

CMS是老年代垃圾收集器,在收集過程中可以與使用者執行緒併發操作。它可以與Serial收集器和Parallel New收集器搭配使用。CMS犧牲了系統的吞吐量來追求收集速度,適合追求垃圾收集速度的伺服器上。引數:-XX:+UseConcMarkSweepGC來開啟CMS。特點:併發收集、降低停頓時間

CMS收集器GC的過程

  • 初始標記:標記GCRoot關聯物件。會觸發Stop The World
  • 併發標記:進行GC Roots Tracing的過程。
  • 重新標記:處理因為初始標記過程中使用者執行緒建立物件而沒有處理的物件標記。
  • 併發清除:標記清除演演算法,清除垃圾。吃階段可能產生浮動垃圾。

G1收集器

G1收集器的設計將整個堆記憶體分為多個大小相等的塊(Region)。任然沿用年輕代、老年代的概念,但相對之前的空間連續,換成了多個Region的集合。G1跟蹤各個Region裡面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在後臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的Region(這也就是Garbage-First名稱的來由)。G1收集器GC的過程

  • 初始標記(Initial Marking) 僅僅只是標記一下GC Roots 能直接關聯到的物件,並且修改TAMS(Nest Top Mark Start)的值,讓下一階段使用者程式併發執行時,能在正確可用的Region中建立物件,此階段需要停頓執行緒,但耗時很短。
  • 併發標記(Concurrent Marking) 從GC Root 開始對堆中物件進行可達性分析,找到存活物件,此階段耗時較長,但可與使用者程式併發執行。
  • 最終標記(Final Marking) 為了修正在併發標記期間因使用者程式繼續運作而導致標記產生變動的那一部分標記記錄,虛擬機器器將這段時間物件變化記錄線上程的Remembered Set Logs裡面,最終標記階段需要把Remembered Set Logs的資料合併到Remembered Set中,這階段需要停頓執行緒,但是可並行執行。
  • 篩選回收(Live Data Counting and Evacuation) 首先對各個Region中的回收價值和成本進行排序,根據使用者所期望的GC 停頓時間來制定回收計劃。

ZGC

JDK11提供的新GC收集器,暫時沒瞭解。

本文由部落格一文多發平臺 OpenWrite 釋出!