目錄
一.GC調(diào)優(yōu)的核心指標(biāo)
1.1吞吐量(Throughput)
1.2延遲(Latency)
1.3內(nèi)存使用量
二.GC調(diào)優(yōu)的方法
2.1監(jiān)控工具
Jstat工具
VisualVm插件
Prometheus + Grafana
2.2診斷原因
GC日志
GC Viewer
GCeasy
2.3常見的GC模式
正常情況
緩存對象過多
內(nèi)存泄漏
持續(xù)的FULL GC
元空間不足導(dǎo)致的FULL GC
三.修復(fù)GC問題
3.1優(yōu)化基礎(chǔ)JVM參數(shù)
參數(shù)1 : -Xmx 和 –Xms
參數(shù)2 : -XX:MaxMetaspaceSize 和 –XX:MetaspaceSize
參數(shù)3 : -Xss虛擬機棧大小
不建議手動設(shè)置的參數(shù)
其他參數(shù)
3.2垃圾回收器的選擇
GC調(diào)優(yōu)
GC調(diào)優(yōu)指的是對垃圾回收(Garbage Collection)進行調(diào)優(yōu)。GC調(diào)優(yōu)的主要目標(biāo)是避免由垃圾回收引起程序性能下降。
GC調(diào)優(yōu)的核心分成三部分:
- 通用JVM參數(shù)的設(shè)置。
- 特定垃圾回收器的JVM參數(shù)的設(shè)置。
- 解決由頻繁的FULL GC引起的程序性能問題。
GC調(diào)優(yōu)沒有唯一的標(biāo)準(zhǔn)答案,如何調(diào)優(yōu)與硬件、程序本身、使用情況均有關(guān)系,重點學(xué)習(xí)調(diào)優(yōu)的工具和方法。
一.GC調(diào)優(yōu)的核心指標(biāo)
所以判斷GC是否需要調(diào)優(yōu),需要從三方面來考慮,與GC算法的評判標(biāo)準(zhǔn)類似:
1.1吞吐量(Throughput)
吞吐量分為業(yè)務(wù)吞吐量和垃圾回收吞吐量
業(yè)務(wù)吞吐量指的在一段時間內(nèi),程序需要完成的業(yè)務(wù)數(shù)量。比如企業(yè)中對于吞吐量的要求可能會是這樣的:
- 支持用戶每天生成10000筆訂單
- 在晚上8點到10點,支持用戶查詢50000條商品信息
保證高吞吐量的常規(guī)手段有兩條:
- 優(yōu)化業(yè)務(wù)執(zhí)行性能,減少單次業(yè)務(wù)的執(zhí)行時間
- 優(yōu)化垃圾回收吞吐量
垃圾回收吞吐量指的是 CPU 用于執(zhí)行用戶代碼的時間與 CPU 總執(zhí)行時間的比值,即吞吐量 = 執(zhí)行用戶代碼時間 /(執(zhí)行用戶代碼時間 + GC時間)。吞吐量數(shù)值越高,垃圾回收的效率就越高,允許更多的CPU時間去處理用戶的業(yè)務(wù),相應(yīng)的業(yè)務(wù)吞吐量也就越高。
1.2延遲(Latency)
延遲指的是從用戶發(fā)起一個請求到收到響應(yīng)這其中經(jīng)歷的時間。
延遲 = GC延遲 + 業(yè)務(wù)執(zhí)行時間,所以如果GC時間過長,會影響到用戶的使用。
1.3內(nèi)存使用量
內(nèi)存使用量指的是Java應(yīng)用占用系統(tǒng)內(nèi)存的最大值,一般通過JVM參數(shù)調(diào)整,在滿足上述兩個指標(biāo)的前提下, 這個值越小越好。
通常這3個指標(biāo)不能同時兼顧
二.GC調(diào)優(yōu)的方法
2.1監(jiān)控工具
Jstat工具
無法精確到GC產(chǎn)生的時間,只能 用于判斷GC是否存在問題
VisualVm插件
Prometheus + Grafana
2.2診斷原因
GC日志
通過GC日志,可以更好的看到垃圾回收細(xì)節(jié)上的數(shù)據(jù),同時也可以根據(jù)每款垃圾回收器的不同特點更好地發(fā)現(xiàn)存在的問題。
- 使用方法(JDK 8及以下):-XX:+PrintGCDetails -Xloggc:文件名
- 使用方法(JDK 9+):-Xlog:gc*:file=文件名
注:?-verbose:gc 是將GC日志輸出到控制臺上,而上面是將GC日志單獨輸出到一個文件
GC Viewer
GCViewer是一個將GC日志轉(zhuǎn)換成可視化圖表的小工具,github地址:https://github.com/chewiebug/GCViewer
使用方法:java -jar gcviewer的jar包 日志文件.log
GCeasy
GCViewer是將GC日志可視化,而GCeasy是業(yè)界首款使用AI機器學(xué)習(xí)技術(shù)在線進行GC分析和診斷的工具。定位內(nèi)存泄漏、GC延遲高的問題,提供JVM參數(shù)優(yōu)化建議,支持在線的可視化工具圖表展示。官方網(wǎng)站:Universal JVM GC analyzer - Java Garbage collection log analysis made easy (gceasy.io)
2.3常見的GC模式
正常情況
特點:呈現(xiàn)鋸齒狀,對象創(chuàng)建之后內(nèi)存上升,一旦發(fā)生垃圾回收之后下降到底部,并且每次下降之后的內(nèi)存大小接近,存留的對象較少。
緩存對象過多
特點:呈現(xiàn)鋸齒狀,對象創(chuàng)建之后內(nèi)存上升,一旦發(fā)生垃圾回收之后下降到底部,并且每次下降之后的內(nèi)存大小接近,處于比較高的位置。
問題產(chǎn)生原因: 程序中保存了大量的緩存對象,導(dǎo)致GC之后無法釋放,可以使用MAT或者HeapHero等工具進行分析內(nèi)存占用的原因。
內(nèi)存泄漏
特點:呈現(xiàn)鋸齒狀,每次垃圾回收之后下降到的內(nèi)存位置越來越高,最后由于垃圾回收無法釋放空間導(dǎo)致對象無法分配產(chǎn)生OutOfMemory的錯誤。
問題產(chǎn)生原因: 程序中保存了大量的內(nèi)存泄漏對象,導(dǎo)致GC之后無法釋放,可以使用MAT或者HeapHero等工具 進行分析是哪些對象產(chǎn)生了內(nèi)存泄漏。
持續(xù)的FULL GC
特點:在某個時間點產(chǎn)生多次Full GC,CPU使用率同時飆高,用戶請求基本無法處理。一段時間之后恢復(fù)正常。
問題產(chǎn)生原因:在該時間范圍請求量激增,程序開始生成更多對象,同時垃圾收集無法跟上對象創(chuàng)建速率,導(dǎo)致持續(xù)地在進行FULL GC。
元空間不足導(dǎo)致的FULL GC
特點:堆內(nèi)存的大小并不是特別大,但是持續(xù)發(fā)生FULL GC。
問題產(chǎn)生原因:元空間大小不足,超過了Java虛擬機設(shè)置的閾值,導(dǎo)致持續(xù)FULL GC回收元空間的數(shù)據(jù)。
三.修復(fù)GC問題
解決GC問題的手段中,前三種是比較推薦的手段,第四種僅在前三種無法解決時選用:
3.1優(yōu)化基礎(chǔ)JVM參數(shù)
參數(shù)1 : -Xmx 和 –Xms
-Xmx參數(shù)設(shè)置的是最大堆內(nèi)存,但是由于程序是運行在服務(wù)器或者容器上,計算可用內(nèi)存時,要將元空間、操作系統(tǒng)、 其它軟件占用的內(nèi)存排除掉。
案例:服務(wù)器內(nèi)存4G,操作系統(tǒng)+元空間最大值+其它軟件占用1.5G,-Xmx可以設(shè)置為2g。
最合理的設(shè)置方式應(yīng)該是根據(jù)最大并發(fā)量估算服務(wù)器的配置,然后再根據(jù)服務(wù)器配置計算最大堆內(nèi)存的值。
-Xms用來設(shè)置初始堆大小,建議將-Xms設(shè)置的和-Xmx一樣大,有以下幾點好處:
- 運行時性能更好,堆的擴容是需要向操作系統(tǒng)申請內(nèi)存的,這樣會導(dǎo)致程序性能短期下降。
- 可用性問題,如果在擴容時其他程序正在使用大量內(nèi)存,很容易因為操作系統(tǒng)內(nèi)存不足分配失敗。
- 啟動速度更快,Oracle官方文檔的原話:如果初始堆太小,Java 應(yīng)用程序啟動會變得很慢,因為 JVM 被迫頻繁執(zhí)行垃圾收集,直到堆增長到更合理的大小。為了獲得最佳啟動性能,請將初始堆大小設(shè)置為與最大堆大小相同。
參數(shù)2 : -XX:MaxMetaspaceSize 和 –XX:MetaspaceSize
- -XX:MaxMetaspaceSize=值 參數(shù)指的是最大元空間大小,默認(rèn)值比較大,如果出現(xiàn)元空間內(nèi)存泄漏會讓操作系統(tǒng)可用內(nèi)存不可控,建議根據(jù)測試情況設(shè)置最大值,一般設(shè)置為256m。當(dāng)元空間大小超過這個值時,會拋出OutOfMemoryError。
- -XX:MetaspaceSize=值 參數(shù)指的是到達(dá)這個值之后會觸發(fā)FULL GC(指的不是初始元空間大?。?, 后續(xù)什么時候再觸發(fā)JVM會自行計算。如果設(shè)置為和MaxMetaspaceSize一樣大,就不會FULL GC,但是對象也無法回收。
參數(shù)3 : -Xss虛擬機棧大小
如果我們不指定棧的大小,JVM 將創(chuàng)建一個具有默認(rèn)大小的棧。大小取決于操作系統(tǒng)和計算機的體系結(jié)構(gòu)。 比如Linux x86 64位 : 1MB,如果不需要用到這么大的棧內(nèi)存,完全可以將此值調(diào)小節(jié)省內(nèi)存空間,合理值為256k – 1m之間。
使用:-Xss256k
不建議手動設(shè)置的參數(shù)
由于JVM底層設(shè)計極為復(fù)雜,一個參數(shù)的調(diào)整也許讓某個接口得益,但同樣有可能影響其他更多接口。
-
-Xmn 年輕代的大小,默認(rèn)值為整個堆的1/3,可以根據(jù)峰值流量計算最大的年輕代大小,盡量讓對象只存放在年輕代,不進入老年代。但是實際的場景中,接口的響應(yīng)時間、創(chuàng)建對象的大小、程序內(nèi)部還會有一些定時任務(wù)等不 確定因素都會導(dǎo)致這個值的大小并不能僅憑計算得出,如果設(shè)置該值要進行大量的測試。G1垃圾回收器盡量不要設(shè)置該值,G1會動態(tài)調(diào)整年輕代的大小。
-
‐XX:SurvivorRatio 伊甸園區(qū)和幸存者區(qū)的大小比例,默認(rèn)值為8。
-
‐XX:MaxTenuringThreshold 最大晉升閾值,年齡大于此值之后,會進入老年代。另外JVM有動態(tài)年齡判斷機制:當(dāng)?survior 區(qū)域的存活對象的總大小占用了?survior 區(qū)域大小的50%(可以通過參數(shù)指定),那么此時將按照這些對象的存活年齡從小到大排序,然后依次累加,當(dāng)累加到對象大小超過50%,則將大于等于當(dāng)前對象年齡的存活對象全部挪到老年代。
其他參數(shù)
- -XX:+DisableExplicitGC?禁止在代碼中使用System.gc(), System.gc()可能會引起FULL GC,在代碼中盡量不要使用。使用DisableExplicitGC參數(shù)可以禁止使用System.gc()方法調(diào)用。
- -XX:+HeapDumpOnOutOfMemoryError 發(fā)生OutOfMemoryError錯誤時,自動生成hprof內(nèi)存快照文件。
- -XX:HeapDumpPath= 指定hprof文件的輸出路徑。
-
打印GC日志
-
JDK8及之前 : -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:文件路徑
-
JDK9及之后 : -Xlog:gc*:file=文件路徑
-
3.2垃圾回收器的選擇
文章來源:http://www.zghlxwxcb.cn/news/detail-818592.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-818592.html
到了這里,關(guān)于JVM實戰(zhàn)篇:GC調(diào)優(yōu)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!