日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gc日志一般关注什么_记一次生产频繁出现 Full GC 的 GC日志图文详解

發(fā)布時間:2025/4/5 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gc日志一般关注什么_记一次生产频繁出现 Full GC 的 GC日志图文详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

場景描述

相信大家都了解 jps、jmap、jstack 等常用 java 堆棧輸出命令,有過 dump、gc 分析的經(jīng)驗(yàn),面試中會經(jīng)常被問到有關(guān) JVM 問題,比如你是否了解你的程序在生產(chǎn)環(huán)境的基礎(chǔ)配置,堆內(nèi)存、棧內(nèi)存怎么設(shè)置的,又是怎么估算的大小,或是垃圾回收器及回收垃圾算法的最佳使用策略。作為項(xiàng)目的核心開發(fā)人員,別把這些事當(dāng)成是架構(gòu)師要干的活,因?yàn)榇a可是你一行一行碼出來的,沒人比你更清楚,你得負(fù)責(zé)從程序開發(fā)、黑白盒測試、項(xiàng)目驗(yàn)收、部署上線、集成交付、運(yùn)維監(jiān)控、用戶體驗(yàn)等環(huán)節(jié)。越大的企業(yè),項(xiàng)目模塊分配的越細(xì),這也并不代表你不需要了解整體系統(tǒng)的性能,其中任何一個環(huán)節(jié)出問題,都可能導(dǎo)致系統(tǒng)無法正常運(yùn)行。

借由這次生產(chǎn)系統(tǒng)頻繁宕機(jī),我們總結(jié)一下 JVM 內(nèi)存模型劃分、JVM 啟動堆內(nèi)存相關(guān)參數(shù)配置及說明、各年齡代的垃圾回收器及回收過程、生產(chǎn) GC 日志解讀與分析、系統(tǒng)運(yùn)行內(nèi)存預(yù)估方法、啟動參數(shù)如何優(yōu)化等。希望通過這篇小記來和大家一起交流、一起學(xué)習(xí)。

正文

2.1 生產(chǎn) GC日志文件

部分截圖如下:

2.2 先看一下 jdk 1.6 的內(nèi)存劃分情況

按年齡劃分為年輕代、老年代、永久代(方法區(qū))、本地方法區(qū)、虛擬機(jī)棧和程序計(jì)數(shù)器。下圖詳細(xì)說明了這幾個內(nèi)存分區(qū)的關(guān)系、JVM 參數(shù)說明、存儲的相關(guān)內(nèi)容及各內(nèi)存分區(qū)的垃圾回收器及垃圾回收算法。

2.3 生產(chǎn)基礎(chǔ)環(huán)境

說明如下:

  • JDK版本:jdk_1.6
  • Web容器:Weblogic

題外話:估計(jì)市面上都是玩微服務(wù)了吧,jdk 版本至少也得 1.8 以上,jdk 1.6 不支持 G1 這么好用的垃圾收集器,也不支持 lambda 表達(dá)式,以及其他好用的特性

2.4 生產(chǎn) JVM 堆內(nèi)存相關(guān)參數(shù)

設(shè)置如下:

// 初始堆大小-Xms4096M// 最大堆大小-Xmx4096M// 持久代最大值-XX:MaxPermSize=1024M//......

題外話:這份配置一看就有點(diǎn)問題,為什么到現(xiàn)在才發(fā)現(xiàn),因?yàn)橄到y(tǒng)之前很少出現(xiàn)問題,之前也未設(shè)置GC日志記錄參數(shù),也未曾關(guān)心 JVM 參數(shù)設(shè)置,大家只是在原有的工程進(jìn)行開發(fā)和維護(hù)。其中 -Xmn 年輕代未配置(-XX:NewRatio 年輕代與年老代所占比值也未配置),-XX:PermSize 持久代初始值未配置(存在動態(tài)擴(kuò)容帶來的性能消耗)等

2.5 截取生產(chǎn)一條 GC 日志

圖解分析如下:

2019-11-20T17:15:38.906+0800:?672725.775:?[GC?2019-11-20T17:15:38.907+0800:?672725.776:?[ParNew:?143735K->15199K(153344K),?0.0485240?secs]?2568043K->2439507K(4177280K),?0.0497750?secs]?[Times:?user=0.20?sys=0.00,?real=0.05?secs]?

從以上 GC 日志文件結(jié)構(gòu)圖解可以清晰看出,線上生產(chǎn)環(huán)境的年輕代總內(nèi)存大小分配約 150M,堆總內(nèi)存大小約 4G,明顯年輕代內(nèi)存分配過小。每次 ParNew GC 老年代變化可以由堆內(nèi)存大小變化和年輕代內(nèi)存大小變化推算。

從下圖 GC 日志可以看出,線上系統(tǒng)出現(xiàn)頻繁 ParNew GC(即年輕代的 Minor GC),平均大約每 5 分鐘進(jìn)行一次 Minor GC,即一天平均執(zhí)行 288 次之多,太可怕了吧!!!唉

題外話:為什么這么頻繁,系統(tǒng)都線上運(yùn)行3年了,當(dāng)初系統(tǒng)上線JVM啟動參數(shù)應(yīng)該是隨便設(shè)置的,呵呵一是系統(tǒng)并發(fā)量不高,二是用戶量不大,三是開發(fā)人員不注重JVM優(yōu)化,四是到前不久才加上GC日志輸出參數(shù),五是 pinpoint 運(yùn)維監(jiān)控系統(tǒng)居然不支持 Minor GC的監(jiān)控,只支持 Full GC 監(jiān)控,呵呵

2.6 CMS (Concurrent Mark Sweep)

CMS 垃圾回收器進(jìn)行一次 Full GC,GC日志部分截圖如下所示:

從上圖可以看出,CMS 垃圾回收器正常運(yùn)行(CMS 垃圾回收觸發(fā)的條件:當(dāng)老年代內(nèi)存達(dá)到92%(3719000K / 4023936K * 100% = 92%),詳情見下圖)。對上圖 CMS GC 進(jìn)行剖析如下:

從圖中可以清晰看到,CMS 對于老年代的垃圾回收分成 7 個階段,每個階段到底做了什么,詳情見以下流程圖所示:

2.7 隨著用戶量增加、系統(tǒng)并發(fā)增加

系統(tǒng)出現(xiàn)了頻繁 Full GC,pinpoint 監(jiān)控內(nèi)存使用情況如下(只能監(jiān)控老年代的 Full GC,而無法監(jiān)控年輕代的 Minor GC,其實(shí) Full GC 之前 Minor GC 執(zhí)行次數(shù)頻率更可怕):

2.8 ParNew + CMS 組合

ParNew(年輕代垃圾回收器) + CMS(老年代垃圾回收器) 回收器組合是在 JDK 1.8 之前大多數(shù) JAVA 企業(yè)級服務(wù)應(yīng)用的最佳選擇,從以下生產(chǎn) GC 日志截圖中可以看到,在 CMS 回收器觸發(fā)時,出現(xiàn)了 promotion failed 和 concurrent mode failure 現(xiàn)象:

針對這兩個現(xiàn)象產(chǎn)生的原因進(jìn)行解讀如下:

  • promotion failed該現(xiàn)象是在進(jìn)行觸發(fā)年輕代 ParNew GC 時,存活的對象在 Survivor 區(qū)放不下,對象只能進(jìn)入老年代,而此時老年代也放不下導(dǎo)致的。
  • concurrent mode failure該現(xiàn)象是在執(zhí)行 CMS 回收器回收垃圾的過程中同時有存活的對象放入老年代,而此時老年代空間不足,或者在做 ParNew GC 的時候,年輕代 Survivor 區(qū)放不下,需要放入老年代,而老年代也放不下而導(dǎo)致的。

2.9 解決方案

針對以上2種現(xiàn)象產(chǎn)生的原因進(jìn)行 JVM 相關(guān)參數(shù)優(yōu)化:

可增大年輕代或者 Survivor 區(qū)的存儲空間

-Xmn1500M-XX:SurvivorRatio=8

或者提前觸發(fā) CMS 垃圾回收和進(jìn)行 5 次 CMS 垃圾回收后整理清除碎片

-XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction=5-XX:+UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction=80

2.10 最后對生產(chǎn)環(huán)境的 JVM 內(nèi)存參數(shù)設(shè)置進(jìn)行優(yōu)化

建議虛擬機(jī)參數(shù)設(shè)置如下:

-Xms4096M-Xmx4096M-Xmn1500M-XX:PermSize=1024M-XX:MaxPermSize=1024M-Xss512K-XX:SurvivorRatio=8-XX:+UseConcMarkSweepGC-XX:+UseParNewGC-XX:+CMSParallelRemarkEnabled-XX:+UseCMSCompactAtFullCollection-XX:CMSFullGCsBeforeCompaction=5-XX:+UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction=80-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-Xloggc:log/gc.log

線上系統(tǒng)內(nèi)存估算方法

3.1 Java對象屬性類型所占字節(jié)大小

列表清單如下:

3.2 Java對象所占JVM內(nèi)存結(jié)構(gòu)

如下圖展示:

可以看到數(shù)組類型對象和普通對象的區(qū)別僅在于 4 字節(jié)數(shù)組長度的存儲區(qū)間。而對象指針究竟是 4 字節(jié)還是 8 字節(jié)要看是否開啟指針壓縮。Oracle JDK 從 6_update_23 開始在 64 位系統(tǒng)上會默認(rèn)開啟壓縮指針。如果要強(qiáng)行關(guān)閉指針壓縮使用 -XX:-UseCompressedOops,強(qiáng)行啟用指針壓縮使用:-XX:+UseCompressedOops。

假如生產(chǎn)訂單某一對象大約30字段,如訂單對象 JavaBeanA ,所占內(nèi)存大小計(jì)算的方法如下所示:

public class ObjectA { int a; // 4 Byte byte b; // 1 Byte String c; // 4 Byte double d; // 8 Byte String e; // 4 Byte // 此處省略25個String對象 25*4 Byte ObjectB objB; // 8 Byte }public class ObjectB { // ... }Size(ObjectA) = Size(對象頭(_mark)) + size(oop指針) + size(數(shù)據(jù)區(qū))Size(ObjectA) = 8 + 4 + 4(int) + 1(byte) + 4(String) * 26 + 8(double) + 7(padding) + 8(ObjectB指針)Size(ObjectA) = 136 字節(jié) = 136 / 1024 kb = 0.133 kb

由此,可以大約估算出你的線上系統(tǒng)每秒產(chǎn)生多少 M 的對象。如果每秒產(chǎn)生 500 個 ObjectA,即大約 0.5 M,那么對于年輕代 1500M 的內(nèi)存,大約需要 3000s 充滿,即 50 min才觸發(fā)一次 Minor GC,也就是說一天大約觸發(fā)24次 Minor GC

總結(jié)

  • 對于生產(chǎn)系統(tǒng),合理增大年輕代內(nèi)存大小,本著盡量減少系統(tǒng) Minor GC,一日最多一次 Full GC 的原則;
  • 優(yōu)化編碼,減少不必要的對象創(chuàng)建,合理定義對象,合理使用和優(yōu)化數(shù)據(jù)結(jié)構(gòu);
  • 優(yōu)化 JVM 內(nèi)存參數(shù)以減少 GC 次數(shù),生產(chǎn)選擇換最優(yōu)垃圾收集器配置策略。

總結(jié)

以上是生活随笔為你收集整理的gc日志一般关注什么_记一次生产频繁出现 Full GC 的 GC日志图文详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。