開發與維運

troubleshoot之:GC調優到底是什麼

簡介

我們經常會聽到甚至需要自己動手去做GC調優。那麼GC調優的目的到底是什麼呢?讓程序跑得更快?讓GC消耗更少的資源?還是讓程序更加穩定?

帶著這些疑問來讀一下這篇文章,將會得到一個系統的甚至是不一樣的結果。

那些GC的默認值

其實GC或者說JVM的參數非常非常的多,有控制內存使用的:

有控制JIT的:

有控制分代比例的,也有控制GC併發的:

當然,大部分的參數其實並不需要我們自行去調整,JVM會很好的動態幫我們設置這些變量的值。

如果我們不去設置這些值,那麼對GC性能比較有影響的參數和他們的默認值有哪些呢?

GC的選擇

我們知道JVM中的GC有很多種,不同的GC選擇對java程序的性能影響還是比較大的。

在JDK9之後,G1已經是默認的垃圾回收器了。

我們看一下G1的調優參數。

G1是基於分代技術的,其實JVM還在開發一些不再基於分代技術的GC算法,比如ZGC,我們可以根據需要來選擇適合我們的GC算法。

GC的最大線程個數

GC是由專門的GC線程來執行的,並不是說GC線程越多越好,這個默認線程的最大值是由heap size和可用的CPU資源動態決定的。

當然你可以使用下面兩個選項來修改GC的線程:

 -XX:ParallelGCThreads=threads 設置STW的垃圾收集線程數

 -XX:ConcGCThreads = n 設置並行標記線程的數量

一般情況下ConcGCThreads可以設置為ParallelGCThreads的1/4。

初始化heap size

默認情況下加初始化的heap size是物理內存的1/64。

你可以使用

 -XX:InitialHeapSize=size

來重新設置。

最大的heap size

默認情況下最大的heap size是物理內存的1/4。

你可以使用:

 -XX:MaxHeapSize

來重新設置。

分層編譯技術

默認情況下分層編譯技術是開啟的。你可以使用:

 -XX:-TieredCompilation

來關閉分層編譯。如果啟用了分層編譯,那麼可能需要關注JIT中的C1和C2編譯器帶來的影響。

我們到底要什麼

魚,我所欲也,熊掌亦我所欲也;二者不可得兼,舍魚而取熊掌者也。--孟子

java程序在運行過程中,會發生很多次GC,那麼我們其實是有兩種統計口徑:

  1. 平均每次GC執行導致程序暫停的時間(Maximum Pause-Time Goal)。
  2. 總的花費在GC上的時間和應用執行時間的比例(Throughput Goal)。

最大暫停時間

單次GC的暫停時間是一個統計平均值,因為單次GC的時間其實是不可控的,但是取了平均值,GC就可以動態去調整heap的大小,或者其他的一些GC參數,從而保證每次GC的時間不會超過這個平均值。

我們可以通過設置:

-XX:MaxGCPauseMillis=<nnn>

來控制這個值。

不管怎麼設置這個參數,總體需要被GC的對象肯定是固定的,如果單次GC暫停時間比較短,可能會需要減少heap size的大小,那麼回收的對象也比較少。這樣就會導致GC的頻率增加。從而導致GC的總時間增加,影響程序的Throughput。

吞吐率

吞吐率是由花費在GC上的時間和應用程序上的時間比率來決定的。

我們可以通過設置:

-XX:GCTimeRatio=nnn

來控制。

如果沒有達到throughput的目標,那麼GC可能會去增加heap size,從而減少GC的執行頻率。但是這樣會增加單次的Maximum Pause-Time。

如果throughput和maximum pause-time的參數同時都設置的話,JVM會去嘗試去動態減少heap size的大小,直到其中的一個目標不能滿足為止。

相對而言,G1更加偏重於最大暫停時間,而ZGC更加偏重於吞吐率。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-diagnostic-gc/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等著您!

Leave a Reply

Your email address will not be published. Required fields are marked *