天天看點

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

作者:大資料架構師

JVM中垃圾回收相關參數介紹

用好JVM的垃圾回收功能有兩個關鍵點:一是需要了解GC算法的原理和實作,二是需要知道JVM到底提供了哪些參數,這些參數用于控制什麼。

然而實際工作更為困難,一方面是要了解參數,需要了解實作細節;另一方面,JDK不斷更新變化,在更新的過程中GC的實作也會發生變化,參數會增加或删除,某些版本中甚至存在一些錯誤的實作,進而導緻參數的含義發生了變化。長期以來,官方提供的參數說明文檔是程式員唯一可以信賴的了解參數作用的文檔。但是官方提供的文檔非常簡單,通常隻有一句簡單的描述,根本不足以滿足調參的需要。這一部分着重介紹JVM提供的參數。

要想用好參數,首先需要了解參數的作用。目前生産環境中使用最為廣泛的是GC還是分代垃圾回收器,不同GC的實作不同,提供的參數也不同。下面以G1為例示範GC調優的一般思路。首先來看看分代對應用的影響,如下圖所示。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

根據圖中介紹,新生代大小會影響停頓時間,Survival的大小,即Form和To空間會影響Minor GC的回收性能,Eden的大小會影響Mutator的配置設定,即執行效率,老生代的大小會影響GC執行性能、停頓時間、記憶體可用空間等,Full GC影響停頓時間。

在GC調優時,應根據應用運作的特點調整相關參數,進而保證應用運作效率高、GC停頓時間短。就G1來說,可以從以下幾方面調整參數。

1)堆空間:最大堆和最小堆、目标停頓時間設定、分區大小。

2)新生代:TLAB大小、YoungPLAB大小、ResizeTLAB設定、ResizePLAB設定、SurvivalAge設定。

3)老生代:并發标記觸發時機、OldPLAB大小,混合回收時老生代參與回收的限制。

4)硬體特性适配:NUMA-Aware、NV-DIMM。

5)代際管理:存儲粒度、并發處理和Minor GC的互動。

6)Minor GC、Mixed GC、Full GC并行的線程數目,以及并行任務均衡和終止機制。

7)引用集處理并發的線程數目。

8)并發标記的線程數目。

9)Java語言中引用回收方式和執行方式。

10)GC過程異常情況的處理:晉升失敗、保留記憶體等。

由此可以看出,GC調優不僅需要掌握相關理論的知識,還需要掌握實作的細節及控制細節的參數。本節将詳細介紹各種GC相關的參數。

由于不同的JDK版本參數有所變化,大家通常使用的是LTS版本的JDK,是以本書僅對JDK 8、JDK 11和JDK 17的參數做總結和梳理。

實作中提供了不同類型的參數,比如生産參數、實驗參數、診斷參數、可動态調整的參數、驗證參數、開發參數等,不同的參數類型主要是告訴使用者參數的作用。

1)生産參數:參數說明中包含product,生産參數表示參數已經非常穩定,經過了長期的驗證,可以用在生産環境中。

2)實驗參數:使用實驗參數時需要添加-XX:+UnlockExperimentalVMOptions才能開啟。這些參數并未經曆過大規模的使用,可能存在一定的性能、穩定性風險。通常這些參數配合一些新開發的特性來使用。

3)診斷參數:在診斷JVM系統的内部行為時使用,使用時需要添加-XX:+Un-lockDiagnosticVMOptions才能開啟。該類參數通常會暴露更多的運作時資訊,以便使用者了解系統。診斷參數通常會影響性能,是以一般不會直接用在生産環境中,通常用于問題定位。

4)可動态調整的參數:JVM的很多參數在啟動後就确定下來,但是還有一些參數可以在系統運作的過程中通過API動态地修改,以便控制或者改變JVM内部運作的機制。

5)驗證參數:JVM還提供了一些以Verify開發的系列參數,這類參數通常用于驗證JVM的運作狀态是否符合運作的預期,是JVM開發和測試非常有用的助手。

6)開發參數:開發參數在普通的Release版本中并不存在,僅僅适用于調試版本。這類參數通常能給JVM開發者提供詳細的資訊,以便開發者了解JVM運作是否符合預期。

GC通用參數

Hotspot中實作了6種垃圾回收器(GC),雖然每種在實作時都有所不同,但是它們還是有一些共同的地方,例如都需要設定堆大小、TLAB、并行/并發線程數等。本章介紹這些通用參數,其中部分參數适用于所有GC,部分參數适用于某幾個GC,少數參數隻适用于某一個GC。

GC生産參數

GC選擇相關參數

Hotspot提供了6種GC,但隻能選擇一種使用。每種GC使用一個參數進行控制,滿足不同場景的訴求。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數使用串行垃圾回收器進行垃圾回收。參數的預設值為false,表示JVM啟動後并不使用串行回收。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數UseParallelGC表示使用并行複制回收新生代,參數UseParallelOldGC表示使用并行标記壓縮回收整個堆空間。

當參數UseParallelGC設定為true時,參數UseParallelOldGC也預設設定為true。如果參數UseParallelGC設定為true,UseParallelOldGC設定為false,則使用并行複制回收新生代,使用串行标記壓縮算法對整個記憶體進行垃圾回收。

在JDK 9之前,并行垃圾回收器是預設的垃圾回收器,即參數UseParallelGC預設為true,從JDK 9開始該參數預設為false。

參數UseParallelOldGC在JDK 17中被删除,當設定UseParallelGC為true時,預設使用并行标記壓縮回收整個堆空間(相當于隻允許UseParallelOldGC為true)。删除參數的原因是并行新生代回收和串行标記壓縮配合沒有任何實際意義,不應該存在這樣的配置。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數表示使用CMS進行垃圾回收。該參數預設使用ParNew回收新生代,使用并發标記清除回收老生代,使用串行标記壓縮回收整個堆空間。參數的預設值為false,表示不使用CMS進行垃圾回收。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數表示使用Shenandoah GC進行垃圾回收。參數的預設值為false,表示不使用Shenandoah進行垃圾回收。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

JVM内部會根據機器的性能來推斷使用哪種GC進行垃圾回收。GC選擇的邏輯如下:

1)參數NeverActAsServerClassMachine為true,使用Serial回收。

2)參數NeverActAsServerClassMachine為false、參數NeverActAsServerClassMachine和AlwaysActAsServerClassMachine同時為true,優先使用G1,當G1不可用時(指的是沒有編譯配置G1)選擇ParallelGC,Parallel GC不可用時(沒有編譯配置Parallel GC)選擇Serial回收。

3)參數NeverActAsServerClassMachine為true,且參數AlwaysActAsServerClassMachine為false,根據硬體資訊确認使用哪種模式,判斷邏輯為:如果CPU核數大于2個并且記憶體大于2GB,則優先使用G1,當G1不可用時選擇Parallel GC,Parallel GC不可用時選擇Serial回收,否則直接使用Serial回收。

另外值得一提的是,參數NeverActAsServerClassMachine的值還與使用的編譯優化模式相關,如果隻開啟了C1,則參數NeverActAsServerClassMachine為true,如果開啟了C2,則參數NeverActAsServerClassMachine為false。

參數NeverActAsServerClassMachine的預設值與平台相關,在X86平台上C1編譯器的預設值為true、C2編譯器的預設值為false,參數AlwaysActAsServerClassMachine的預設值為false。

提供兩個參數的原因是不同的平台上OS獲得的硬體資訊會有差别,這可能導緻不同平台上JVM的行為不一緻,如果發現這樣的情況,且需要保證多平台行為的一緻性,可以直接通過這兩個參數控制。

GC工作線程相關參數

除了串行回收,Parallel GC、CMS、G1、ZGC和Shenandoah中涉及多個線程并行或者并發工作,線程個數可以通過參數控制,本節介紹相關參數。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定并行GC工作線程的數目,參數的預設值為0。如果參數沒有設定(即保持預設值),JVM根據機器硬體計算得到并行工作線程數。不同的GC計算略有不同,如下:

對于Parallel GC/CMS/G1/Shenandoah,計算公式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

對于ZGC,計算公式如下:

ParallelGCThreads = ncpus×60%

其中ncpus為CPU的核數。

根據CPU個數計算并行線程數的目的是防止在一些高性能計算機上CPU核數非常多,比如可以達到128個,如果不對并行線程數做限制,并行工作線程會非常多,可能會導緻應用性能下降。性能下降的主要原因是在并行工作時多線程可能會發生任務均衡,同時多個線程需要同步達到終止狀态,當并行線程過多時,可能會因為任務竊取效率低下及大量線程同步而出現整體性能下降。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定并發GC工作線程的數目,參數的預設值為0。JVM内部要求ConcGC-Threads小于ParallelGCThreads,如果設定參數,必須為小于ParallelGCThreads的值;如果沒有設定參數,JVM會根據不同的GC計算參數的值。計算方法如表9-1所示。

表9-1 不同GC計算參數ConcGCThreads的方法

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數
JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定是否允許動态調整并行/并發GC工作線程的數目。對于不同的GC,該參數的作用範圍不同。具體如下:

1)Parallel GC中可以調整并行工作線程數,影響Minor GC和Full GC。

2)G1中可以調整并發标記的線程數,也可以調整Refine線程數,還可以調整并行工作線程數。

3)CMS中可以調整并行工作線程數,但是不能調整并發線程數目。

4)Shenandoah中可以調整并行和并發工作線程數。

5)ZGC不受此參數控制,實作了額外的控制邏輯。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

這是一種在允許GC工作線程動态調整的實作中(參數UseDynamicNumberOfGCThreads為true時)智能推斷GC線程個數的方法。

具體方法為:使用整個堆記憶體的大小除以參數HeapSizePerGCThread,得到線程的個數,假定用此種方式推測出GC工作線程個數為Number_Worker1。該方法的邏輯是,假設每個GC工作線程處理的記憶體大小為HeapSize-PerGCThread。

GC工作線程調整的另外一種智能推斷GC線程個數的方法如下:将正在允許的Java線程個數的兩倍作為一個上限,假定此種方式推測出GC工作線程的個數為Number_Worker2。

動态GC工作線程的預測值為Min(Max(Number_Worker1,Number_Worker2),ParallelGC- Threads)。

參數HeapSizePerGCThread在不同的平台中的預設值不同,在32位系統中的預設值為128MB,在64位系統中的預設值為128MB×1.3(注意1.3是一個平台系數)。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數表示GC線程在運作的時候可以記錄線程運作的時間資訊,使用一個數組記錄這些資料,當資料輸出之後,所有的資料将被清除。該參數隻有在debug的日志下才會生效。參數的預設值為200,表示每間隔200毫秒記錄一次資訊。

由于JVM内部重構了參數動态調整的實作,是以該參數不再有效,在JDK14中被移除。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于指定ncpu的值。該值會影響并行/并發線程的個數。如果指定了該參數,JVM将不再使用運作環境中真實CPU的個數。參數的預設值為-1,表示不指定ncpu的值,由JVM通過系統API獲得真實的CPU個數。

注意,運作環境可能是Docker容器,也可能是真實的實體機。

記憶體設定相關參數

Hotspot提供了參數用于控制堆空間大小、分代GC各個代的大小等。本節介紹相關參數。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定JVM最大可以使用的實體記憶體,适用于所有的垃圾回收器。該參數是平台相關的參數(例如在X86 32位系統中該值預設為1GB)。當沒有設定最大堆空間時,使用該參數智能推斷堆空間大小。如果參數沒有設定,将使用作業系統API擷取系統的實體記憶體,用于進行堆空間的計算。機關是B,可以相容G/K/M等符号,如設定為4GB。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數MaxHeapSize和Xmx用于設定JVM最大可用的堆空間,在32位系統中,參數的預設值為96MB。若沒有設定參數MaxHeapSize,則會通過可用實體記憶體(記為physical_memory)來估算并修正預設值。修正的方式如下:

1)當physical_memory或者MaxRAM指定的可用實體空間小于系統參數預設值的2倍時(例如32位系統,實體空間小于96×2 = 192MB),

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

2)否則

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數MaxRAMPercentage和參數MinRAMPercentage的預設值分别是25和50,含義是MaxHeapSize理想空間是實體空間的25%,如果實體空間特别小,那麼MaxHeapSize不少于實體空間的50%。

參數MaxRAMFraction和參數MaxRAMPercentage的作用類似,兩者存在換算關系,如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數MinRAMFraction和參數MinRAMPercentage的作用類似,兩者存在換算關系,如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數Xmx、MaxRAMFraction和MinRAMFraction在JDK 10之後被标記為丢棄,而僅使用MaxHeapSize、MaxRAMPercentage和MinRAMPercentage,原因是後者更為直覺、便于了解。當然這兩類參數目前都還有效,如果同時設定,那麼隻有後者生效。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于調整堆空間自動計算的邊界值。當MaxHeapSize沒有設定時,則JVM會自動計算參數MaxHeapSize,如果設定了參數ErgoHeapSizeLimit,那麼JVM會取計算值和ErgoHeapSizeLimit兩個之中較小的那個用于最終的計算中。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數InitialHeapSize用于設定JVM啟動後初始化的堆空間大小。如果初始化堆空間沒有設定,則JVM會通過可用實體記憶體來估算InitialHeapSize,計算方式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數InitialRAMPercentage的預設值為1.526%(即1/64)。參數InitialRAMFraction和參數InitialRAMPercentage的作用類似,兩者存在換算關系,如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數InitialRAMFraction在JDK 10之後被标記為丢棄。

廢棄InitialRAMFraction使用InitialRAMPercentage的原因是後者更為直覺,便于了解。兩個參數目前都還有效,如果兩個參數同時設定,則隻有參數InitialRAMPercentage生效。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數MinHeapSize和Xms用于設定JVM啟動後最小可用的堆空間大小。如果最小堆空間沒有設定,則JVM會通過可用實體記憶體來估算最小堆空間。計算方式如下:

MinHeapSize = Min(InitialHeapSize, OldSize + NewSize)其中OldSize和NewSizie也是來自參數值。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

這兩個參數用于設定分代垃圾回收器新生代的大小,NewSize的預設值在32位系統中為1MB。如果沒有設定NewSize,那麼JVM會通過InitialHeapSize來估算NewSize。計算方式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定分代垃圾回收器新生代的最大值(新生代最多可用的空間大小)。如果MaxNewSize沒有設定,則MaxNewSize的計算方式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于設定分代垃圾回收器老生代的大小,OldSize的預設值在32位系統中為4MB。如果沒有設定老生代大小,則JVM會通過MaxHeapSize來估算OldSize。計算方式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數根據比例設定新生代大小,預設值為2。如果沒有設定MaxNewSize和NewSize,可以使用NewRatio計算MaxNewSize和NewSize;如果設定了MaxNewSize和NewSize,則直接丢棄參數NewRatio。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在分代垃圾回收器中,新生代采用複制算法,複制算法中有一個Eden和兩個Survivor分區,該參數用于計算Survivor的大小,公式為

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數的預設值為8,表示Survivor分區占整個新生代大小的1/10。

在Parallel GC中,該參數不直接影響Survivor分區的大小,而是通過MinSurvivorRatio和InitialSurvivorRatio設定Survivor分區大小。而G1/ZGC/Shenandoah是分區設定,不需要該參數控制。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在64位系統中,若設定了UseCompressedOops,則Java的堆從位址HeapBaseMinAddress開始,參數的預設值是2GB。

壓縮指針僅适用于堆空間小于32GB的情況。在JVM内部的很多地方使用malloc進行記憶體配置設定,這些配置設定的記憶體都将在HeapBaseMinAddress之下。是以在實際應用中如果遇到本地堆棧的溢出,則可以調整該參數值,避免本地堆和Java堆的沖突。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于動态調整新生代和老生代的大小,參數的預設值為true。僅适用于Parallel GC,在CMS中即使将該參數設定為true,也會重新定義為false。

在垃圾回收(包含Minor GC或者Full GC)執行的最後,可以根據統計的曆史資料來動态地調整各個空間的大小。

當設定參數UseAdaptiveSizePolicy後,會在暫停時間和吞吐量之間取得一個平衡,然後調整新生代和老生代大小。停頓時間和吞吐量的平衡點在于:

1)一個合适的最大GC停頓時間。

2)一個合适的最大Minor GC停頓時間。

3)一個合适的應用程式吞吐量。

4)一個合适的額外記憶體空間占用。

注意

在調整記憶體大小時,上述4種方法是有優先級的。停頓時間優先級最高,其次是吞吐量,最後是額外空間占用的情況。隻有前面的調整政策不滿足的情況下才會使用後面的調整政策。政策如下:

1)如果GC停頓時間大于目标暫停時間(通過參數設定,-XX:MaxGCPauseMillis =nnn)或者Minor GC停頓時間大于目标暫停時間(-XX:MaxGCMinorPauseMillis = nnn),則降低新生代大小以比對目标暫停時間。

2)否則,如果暫停時間合适,則考慮應用的吞吐量,通過增大新生代的大小滿足吞吐量。

3)否則,如果允許調整JVM本地記憶體使用,則增加新生代的大小,減少Full GC的次數。

在調整過程中使用4個參數,分别如下:

-XX:MaxGCPauseMillis=nnn:不能設定得過小,否則會阻礙吞吐量。如果不設定,那麼不使用停頓時間調整新生代、老生代大小。

-XX:MaxGCMinorPauseMillis=nnn:不能設定得過小,否則會阻礙吞吐量。如果不設定,那麼不使用停頓時間調整新生代大小。

-XX:GCTimeRatio=nnn:用在垃圾回收上的時間不超過應用運作時間的

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

。參數的預設值為99,表示垃圾回收時間不應該超過整體時間的1%。

UseAdaptiveSizePolicyFootprintGoal:是否允許調整新生代和老生代的劃分比例,以減少JVM本地記憶體消耗,預設值為true。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數允許調整新生代和老生代的大小以減少JVM本地記憶體的消耗。預設值為true,表示允許調整新生代和老生代的大小。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數允許在Minor GC執行結束後動态地計算新生代、老生代的大小劃分,僅适用于Parallel GC。該參數需要在參數UseAdaptiveSizePolicy為true時才有效。參數的預設值為true,表示在執行Minor GC後調整新生代、老生代的大小劃分。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數允許在Full GC執行結束後動态地計算新生代、老生代的大小劃分,僅适用于Parallel GC。該參數需要在參數UseAdaptiveSizePolicy為true時才有效。參數的預設值為true,表示在執行Full GC後調整新生代、老生代的大小劃分。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

執行允許在調用System.gc的GC後動态地計算新生代、老生代的大小的劃分(包含Minor GC和Full GC,Minor GC僅用于Full GC觸發後,在執行過程中執行一次額外的Minor GC才符合條件,一般的Minor GC不滿足該條件。參數ScavenageBeforeFullGC為true,Parallel GC會在Full GC執行前執行一次Minor GC),僅适用于Parallel GC。該參數必須在參數UseAdaptiveSizePolicy為true時才有效。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

以上參數是新生代、老生代的大小劃分的控制方法之一,使用吞吐量作為目标來動态地調整(吞吐量由GCTimeRatio控制)新生代、老生代的大小劃分。

參數AdaptiveSizeThroughPutPolicy将根據吞吐量調整新生代或者老生代的大小,基本邏輯是:

新生代或者老生代空間變大,垃圾回收發生的機率變小,吞吐量将提高。該參數隻會增加記憶體空間的大小,不會縮小記憶體空間的大小。當Mutator的吞吐量低于目标門檻值時:

1)參數值設定為0時,直接增加的記憶體大小,且增加的大小通過一個簡單公式調整計算。

2)參數值設定為1時,在執行Minor GC後調整新生代的大小。需要通過預測模型來估算新生代的吞吐量變化情況,如果預測吞吐量還會繼續增加,則暫時不調整新生代記憶體的大小,否則通過一個簡單的公式來調整大小;在執行Full GC後調整老生代的大小,需要通過預測模型來估算老生代的吞吐量變化情況,如果預測吞吐量還會繼續增加,則暫時不調整老生代記憶體大小,否則通過一個簡單公式來調整大小。由于預測模型可能會因為沒有足夠的曆史資料而出現模型預測誤差,是以在模型預測的情況下引入了一個額外的參數AdaptiveSize-PolicyInitializingSteps,控制隻有在收集一定次數的資料後才可以使用模型進行預測。

參數AdaptiveSizeThroughPutPolicy的預設值為0,表示直接調整,無須考慮吞吐量變化的情況;參數AdaptiveSizePolicyInitializingSteps的預設值為20,表示隻有經過20次記憶體增加後才會使用模型進行預測。

記憶體調整過程涉及兩個部分:其一,通過公式調整記憶體的值,公式是什麼;其二,預測模型預測吞吐量的變化,預測模型是什麼。這兩部分都涉及一些參數。下面結合參數分别看一看公式和預測模型及模型的使用。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

Minor GC和Full GC後控制Eden增加。計算公式使用了3個參數:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

Eden最後增加的大小為eden_scaled。

其中參數YoungGenerationSizeIncremen的預設值為20,根據公式,Eden每次調整最少增加20%(記為基礎增幅);參數YoungGenerationSizeSupplement的預設值為80,表示JVM運作早期Eden會額外增加80%(記為額外增幅),但是随着Minor GC執行次數的增加,這個值會逐漸變小,最後額外增幅會變成0。

參數YoungGenerationSizeSupplementDec-ay的預設值為8,控制額外增幅衰減的粒度,表示每執行8次Minor GC,額外增幅減少一半,根據計算可以得到大概發生56次Minor GC後,額外增幅變為0。

在公式中用到了eden_desired、minor_gc_cost、full_gc_cost,它們是Parallel GC運作過程中Eden、Minor GC和Full GC的預測值。下面的參數會介紹它們具體的計算方法。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

Full GC後控制老生代增加。計算公式使用了3個參數:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

Old最後增加的大小為old_scaled。

其中參數TenuredGenerationSizeIncrement的預設值為20,根據公式表示Old每次調整最少增加promoted_desired的20%(記為基礎增幅);參數TenuredGenerationSizeSupplement的預設值為80,表示JVM運作早期Old會額外增加promoted_desired的80%(記為額外增幅),但是随着Full GC執行次數的增加,這個值會逐漸變小,最後額外增幅會變成0。參數TenuredGenerationSizeSupplementDecay的預設值為2,控制額外增幅衰減的粒度,表示每執行2次Full GC,額外增幅減少一半,根據計算可以得到大概發生14次Full GC後額外增幅變為0。

在公式中使用了promoted_desired、minor_gc_cost、full_gc_cost,它們是Parallel GC運作過程中promoted_desired(預期晉升記憶體大小)、Minor GC和Full GC相關的預測值,下面的參數會介紹它們具體的計算方法。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在Minor GC和Full GC執行過程中會收集一些曆史資料,然後根據曆史資料預測趨勢值。在預測的時候使用衰減平均值來計算,在衰減計算中可以設定兩個參數Weight和Padding,分别表示最新資料的權重、預測值調整衰減方差的倍數。

在上面新生代Eden和Old調整的公式中用到eden_desired、promoted_desired、minor_gc_cost和full_gc_cost,它們可以分為兩類:大小的預測、時間的預測。大小的預測(eden_desired和promoted_desired)使用參數AdaptiveSizePolicyWeight和PromotedPadding,時間的預測(minor_gc_cost和full_gc_cost)使用參數AdaptiveTimeWeight和PausePadding。

其中eden_desired和promoted_desired使用的曆史資料是每次Minor GC執行前Eden的大小及上一次執行Minor GC時所有晉升對象的大小(promoted)。收集每次Eden、promoted資料的建立序列,然後預測eden_desired和promoted_desired的值,預測時使用了參數AdaptiveSizePolicyWeight和PromotedPadding。

而minor_gc_cost和full_gc_cost是通過公式變化得到的。首先收集Minor GC、Full GC的執行時間(分别記為minor_pause、full_pause),然後再收集GC執行間隔的時間(記為interval),minor_gc_cost和full_gc_cost的計算方法如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

收集每次minor_gc_cost、full_gc_cost資料的建立序列,然後預測minor_gc_cost、full_gc_cost的值,預測時使用了參數AdaptiveTimeWeight和PausePadding。

參數AdaptiveSizePolicyWeight、PromotedPadding、AdaptiveTimeWeight和PausePadding的預設值分别為10、3、25、1,分别表示在size預測時最新資料的權重為10%,使用3個衰減均方差調整預測值;在時間預測時最新資料的權重為25%,使用1個衰減均方差調整預測值。

除此之外,在參數AdaptiveSizeThroughPutPolicy為1時,該模型建立預測吞吐量的變化。具體方法是:建立Minor GC和Full GC記憶體使用和停頓時間的關系。Minor GC使用序列{(eden_size1, minor_pause1), (eden_size2,minor_pause2), …, (eden_sizei, minor_pausei)},Full GC使用序列{(promoted_size1, full_pause1), (promoted_size2, full_pause2), …,(promoted_sizei, full_pausei)},通過序列建立size和pause之間的關系,然後可以預測吞吐量是否發生變化。預測時使用最小二乘法建立size和pause的函數關系。下面簡單介紹一下最小二乘法。

給定一個點序列(x1, y1), (x2, y2), …, (xn, yn),尋找一條直線y =f(x) = ax + b,使得所有的點到直線的距離最小,然後再根據獲得的直線預測未來的值。最小二乘法的關鍵是尋找函數的參數a和b。點序列到直線的距離記為d,則

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

要使得d最小,可以對a和b分别求導,并讓其等于0,此時d最小,是以可以建立以下微分方程:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

由此方程可以得到a和b的計算公式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

a和b公式中的n表示n個抽樣資料。

根據最小二乘法的公式可以計算得到a和b,分别表示系數和截距。

1)a大于0,直線斜率為正,表示吞吐量的變化仍然是增加的。

2)a小于0,直線斜率為負,表示吞吐量的變化開始減少。

是以在模型預測時隻要判斷斜率a的變化情況就可以知道吞吐量的變化情況。當斜率a大于0時,由于吞吐量仍然增加,是以不調整Eden或者Old的大小;隻有在斜率a小于0時,表示吞吐量開始減少,增加Eden或者Old的大小才可以提高吞吐量。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在根據停頓時間和記憶體使用效率調整政策時,會減少Eden或者Old的大小。在減少Eden或者Old的大小時,為了避免導緻Mutator性能下降,使用了額外的參數控制減少的比例。真實減少的數值重用了eden_scaled和old_scaled的計算方法,減少值分别記為eden_decrement和old_decrement,公式如下:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數AdaptiveSizeDecrementScaleFactor的預設值為4,表示減少值是增加值的1/4。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

以上參數用于設定在執行Minor GC和Full GC後,根據吞吐量調整新生代、老生代的大小時是否調整full_gc_cost的值,進而影響後續預測值的計算。

在老生代減少的計算過程中可能會因為Full GC發生的頻率較低,進而導緻full_gc_cost計算出現很大的誤差。特别是會出現觸發過幾次Full GC後不再觸發的情況,對于這樣的情況,可以控制在計算full_gc_cost時是否進行額外的調整。

參數UseAdaptiveSizeDecayMajorGCCost為true,表示允許在滿足一定條件時對full_gc_cost進行調整,參數AdaptiveSizeMajorGCDecayTimeScale控制條件,具體條件是當上一次執行Full GC到現在為止過去的時間(記為time_since_last_full_gc)大于一定的門檻值,則調整full_gc_cost。門檻值(threshold)通過公式計算得到:

threshold = AdaptiveSizeMajorGCDecayTimeScale×full_gc_costfull_gc_cost的調整公式為:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

參數UseAdaptiveSizeDecayMajorGCCost的預設值為true,表示允許調整full_gc_cost的值,參數AdaptiveSizeMajorGCDecayTimeScale的預設值為10,表示距離上次full_gc發生的時間至少是full_gc_cost的10倍才會進行調整。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

新生代中的對象經過一定次數的Minor GC以後,如果對象仍然存活才會晉升到老生代。參數表示經過Minor GC最多的次數的門檻值,參數的預設值為15。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

晉升門檻值的初始值,參數的預設值為7。

在Parallel GC中,如果UseAdaptiveSizePolicy為true,則初始值為7。

如果UseAdaptive-SizePolicy為false,則初始值為MaxTenuringThreshold。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數控制是否允許動态調整新生代中Survivor分區的大小及對象晉升的門檻值,僅适用于Parallel GC。該參數在參數UseAdaptiveSizePolicy設定為true時才能生效。

Survivor分區的大小根據Survivor分區的曆史值通過衰減平均法進行預測。

晉升門檻值的調整與參數ThresholdTolerance相關。調整的方法根據MinorGC和Full GC回收時間(即minor_gc_cost和full_gc_cost)決定。參數ThresholdTolerance用于控制兩個停頓時間的比例,晉升門檻值調整的方法為:

1)如果

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

,則增加晉升門檻值。

2)如果

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

,則減小晉升門檻值。

參數UsePSAdaptiveSurvivorSizePolicy的預設值為true。參數ThresholdTolerance的預設值為10,表示minor_gc_cost和full_gc_cost的比值在±10%内不調整門檻值。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在Parallel GC中會動态地計算Survivor分區的大小。需要收集Survivor分區的大小,然後采用衰減平均預測。為了修正預測的準确性,使用參數AdaptiveSizePolicyWeight和SurvivorPadding,分别控制最新Survivor分區的大小的權重及預測時調整衰減均方差的倍數。

參數SurvivorPadding的預設值為3,表示預測Survivor分區大小使用3倍的衰減均方差進行調整。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數允許動态調整Parallel GC新生代和老生代的邊界(不僅僅是大小,關于邊界的調整請參見5.1.1節),這将增大或者減小新生代或者老生代最大的可用空間。該參數在參數UseAdaptiveSizePolicy設定為true時才能生效。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

該參數用于在Parallel GC中控制是否輸出記憶體調整前後的資訊。該參數值為0,不輸出。參數值不為0,表示每間隔AdaptiveSizePolicyOutputInterval次GC後進行一次輸出。參數的預設值為0。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

JVM使用本地記憶體的估算值,預設值為256MB。該值不會影響JVM的運作,僅僅用于資訊輸出。無須設定。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在Parallel GC中,因為新生代和老生代可以動态調整(UseAdaptiveSizePolicy設定為true),其中Survivor的大小可以通過公式計算得到:

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

如果設定參數MinSurvivorRatio,那麼參數值必須大于等于3,如果小于3,該值會被強制設定為3。參數的預設值為3,表示在允許調整Survivor分區的情況下,表示Survivor分區為新生代的1/3。當SurvivorRatio設定而該值沒有設定時,MinSurvivorRatio = SurvivorRatio + 2。

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

在Parallel GC中,當新生代和老生代不能調整時,Survivor設定為

JVM中垃圾回收GC生産參數,GC選擇+工作線程+記憶體設定相關參數

如果設定參數InitialSurvivorRatio,那麼參數值必須大于等于3,如果小于3,該值會被強制設定為3。參數的預設值為8,表示在不允許調整Survivor分區的情況下,Survivor分區最大為新生代的1/8。

另外,當設定SurvivorRatio,而沒有設定參數InitialSurvivorRatio時,MinSurvivorRatio = SurvivorRatio + 2。

本篇文章給大家講解的内容是JVM中垃圾回收相關參數介紹:GC通用參數,GC生産參數,GC選擇+GC工作線程+記憶體設定相關參數

  1. 下篇文章給大家講解的内容是JVM中垃圾回收相關參數介紹:GC通用參數,GC生産參數,停頓時間+執行效率相關參數
  2. 感謝大家的支援!

繼續閱讀