<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          GC 日志打印最佳實(shí)踐

          共 9925字,需瀏覽 20分鐘

           ·

          2021-06-12 13:26

          生產(chǎn)環(huán)境上,或者其他要測(cè)試 GC 問(wèn)題的環(huán)境上,一定會(huì)配置上打印 GC 日志的參數(shù),便于分析 GC 相關(guān)的問(wèn)題。

          但是可能很多人配置的都不夠“完美”,要么是打印的內(nèi)容過(guò)少,要么是輸出到控制臺(tái),要么是一個(gè)大文件被覆蓋,要么是……

          本文帶你一步一步,配置一個(gè)完美的 GC 日志打印策略

          打印內(nèi)容

          為了保留足夠多的“現(xiàn)場(chǎng)證據(jù)”,最好是把 GC 相關(guān)的信息打印的足夠完整。而且你的程序真的不差你GC時(shí)打印日志I/O消耗的那點(diǎn)性能

          打印基本 GC 信息

          打印 GC 日志的第一步,就是開(kāi)啟 GC 打印的參數(shù)了,也是最基本的參數(shù)。

          -XX:+PrintGCDetails -XX:+PrintGCDateStamps

          打印對(duì)象分布

          為了分析 GC 時(shí)的晉升情況和晉升導(dǎo)致的高暫停,不看對(duì)象年齡分布日志怎么行

          -XX:+PrintTenuringDistribution

          輸出內(nèi)容示例:

          Desired survivor size 59244544 bytes, new threshold 15 (max 15)
          - age   1:     963176 bytes,     963176 total
          - age   2:     791264 bytes,    1754440 total
          - age   3:     210960 bytes,    1965400 total
          - age   4:     167672 bytes,    2133072 total
          - age   5:     172496 bytes,    2305568 total
          - age   6:     107960 bytes,    2413528 total
          - age   7:     205440 bytes,    2618968 total
          - age   8:     185144 bytes,    2804112 total
          - age   9:     195240 bytes,    2999352 total
          - age  10:     169080 bytes,    3168432 total
          - age  11:     114664 bytes,    3283096 total
          - age  12:     168880 bytes,    3451976 total
          - age  13:     167272 bytes,    3619248 total
          - age  14:     387808 bytes,    4007056 total
          - age  15:     168992 bytes,    4176048 total

          GC 后打印堆數(shù)據(jù)

          每次發(fā)生 GC 時(shí),對(duì)比一下 GC 前后的堆內(nèi)存情況,更直觀

          -XX:+PrintHeapAtGC

          輸出內(nèi)容示例:

          {Heap before GC invocations=0 (full 0):
           garbage-first heap   total 1024000K, used 324609K [0x0000000781800000, 0x0000000781901f40, 0x00000007c0000000)
            region size 1024K, 6 young (6144K), 0 survivors (0K)
           Metaspace       used 3420K, capacity 4500K, committed 4864K, reserved 1056768K
            class space    used 371K, capacity 388K, committed 512K, reserved 1048576K
          Heap after GC invocations=1 (full 1):
           garbage-first heap   total 1024000K, used 21755K [0x0000000781800000, 0x0000000781901f40, 0x00000007c0000000)
            region size 1024K, 0 young (0K), 0 survivors (0K)
           Metaspace       used 3420K, capacity 4500K, committed 4864K, reserved 1056768K
            class space    used 371K, capacity 388K, committed 512K, reserved 1048576K
          }

          打印 STW 時(shí)間

          暫停時(shí)間是 GC 最重要的指標(biāo),肯定不能少

          -XX:+PrintGCApplicationStoppedTime

          輸出內(nèi)容示例:

          Total time for which application threads were stopped: 0.0254260 seconds, Stopping threads took: 0.0000218 seconds

          打印 safepoint 信息

          進(jìn)入STW階段之前,需要要找到一個(gè)合適的 safepoint ,這個(gè)指標(biāo)一樣很重要(非必選,出現(xiàn) GC 問(wèn)題時(shí)最好加上此參數(shù)調(diào)試)

          -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1

          輸出內(nèi)容示例:

                   vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count
          0.371: ParallelGCFailedAllocation       [      10          0              0    ]      [     0     0     0     0     7    ]  0   
          Execute full gc...dataList has been promoted to cms old space
                   vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count
          0.379: ParallelGCSystemGC               [      10          0              0    ]      [     0     0     0     0    16    ]  0   
                   vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count
          0.396: no vm operation                  [       9          1              1    ]      [     0     0     0     0   341    ]  0   

          打印 Reference 處理信息

          強(qiáng)引用/弱引用/軟引用/虛引用/finalize 方法萬(wàn)一有問(wèn)題,不得打印出來(lái)看看?

          -XX:+PrintReferenceGC

          輸出內(nèi)容示例:

          2021-02-19T12:41:30.462+0800: 5072726.605: [SoftReference, 0 refs, 0.0000521 secs]
          2021-02-19T12:41:30.462+0800: 5072726.605: [WeakReference, 0 refs, 0.0000069 secs]
          2021-02-19T12:41:30.462+0800: 5072726.605: [FinalReference, 0 refs, 0.0000056 secs]
          2021-02-19T12:41:30.462+0800: 5072726.605: [PhantomReference, 0 refs, 0 refs, 0.0000059 secs]
          2021-02-19T12:41:30.462+0800: 5072726.605: [JNI Weak Reference, 0.0000131 secs], 0.4635293 secs]

          完整參數(shù)

          # requireds
          -XX:+PrintGCDetails 
          -XX:+PrintGCDateStamps 
          -XX:+PrintTenuringDistribution 
          -XX:+PrintHeapAtGC 
          -XX:+PrintReferenceGC 
          -XX:+PrintGCApplicationStoppedTime

          # optional
          -XX:+PrintSafepointStatistics 
          -XX:PrintSafepointStatisticsCount=1

          輸出方式

          上面只是定義了打印的內(nèi)容,默認(rèn)情況下,這些日志會(huì)輸出到控制臺(tái)(標(biāo)準(zhǔn)輸出)。那如果你的程序日志也輸出到控制臺(tái)呢,這個(gè)日志內(nèi)容就會(huì)很亂,分析起來(lái)很麻煩。如果你是追加的方式(比如 tomcat 的 catalina.out 就是追加),這個(gè)文件會(huì)越來(lái)越大,分析起來(lái)就要命了。

          所以需要一種分割日志的機(jī)制,這個(gè)機(jī)制嘛……JVM自然是提供的。

          JVM 的日志分割

          JVM提供了幾個(gè)用于分割 GC 日志的參數(shù):

          # GC日志輸出的文件路徑
          -Xloggc:/path/to/gc.log
          # 開(kāi)啟日志文件分割
          -XX:+UseGCLogFileRotation 
          # 最多分割幾個(gè)文件,超過(guò)之后從頭開(kāi)始寫(xiě)
          -XX:NumberOfGCLogFiles=14
          # 每個(gè)文件上限大小,超過(guò)就觸發(fā)分割
          -XX:GCLogFileSize=100M

          按照這個(gè)參數(shù),每個(gè)GC日志只要超過(guò)20M就會(huì)進(jìn)行分割,最多分割5個(gè)文件,文件名依次是gc.log.0,gc.log.1,gc.log.2,gc.log.3,gc.log.4, .....

          看似很美好,幾行配置就搞定了輸出文件的問(wèn)題。但是這種方式有一些問(wèn)題:

          • -Xloggc 方式指定的日志文件,是覆蓋寫(xiě)的方式,每次啟動(dòng)都會(huì)覆蓋,歷史日志會(huì)丟失
          • 當(dāng)超過(guò)最大分割數(shù)后,會(huì)從第0個(gè)文件開(kāi)始重新寫(xiě)入,而且是覆蓋
          • -XX:NumberOfGCLogFiles 并不能設(shè)置為無(wú)限

          這個(gè)覆蓋的問(wèn)題就有點(diǎn)惡心了,每次啟動(dòng)覆蓋之前的歷史日志……這誰(shuí)能忍?

          使用時(shí)間戳命名文件

          于是有另一種解決方案。不使用 JVM 提供的日志分割功能,而是每次啟動(dòng)用時(shí)間戳命名日志文件,這樣可以每次啟動(dòng)都使用不同的文件,就不會(huì)出現(xiàn)覆蓋的問(wèn)題了。

          # 使用-%t作為日志文件名
          -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc-%t.log

          # 生成的文件名是這種:gc-2021-03-29_20-41-47.log

          可是這樣就完美嗎?

          雖然沒(méi)有覆蓋的問(wèn)題,但由于沒(méi)有日志分割的功能,每次啟動(dòng)后只有一個(gè)GC日志文件,單個(gè)日志文件可能會(huì)非常巨大。過(guò)大的日志文件分析起來(lái)是很麻煩的,必須得分割。

          二者結(jié)合

          這里只需要稍微調(diào)整一下策略,將 JVM 分割和時(shí)間戳命名兩種方案結(jié)合,就可以得到最優(yōu)的方式了。

          # GC日志輸出的文件路徑
          -Xloggc:/path/to/gc-%t.log
          # 開(kāi)啟日志文件分割
          -XX:+UseGCLogFileRotation 
          # 最多分割幾個(gè)文件,超過(guò)之后從頭開(kāi)始寫(xiě)
          -XX:NumberOfGCLogFiles=14
          # 每個(gè)文件上限大小,超過(guò)就觸發(fā)分割
          -XX:GCLogFileSize=100M

          配置時(shí)間戳作文 GC 日志文件名的同時(shí),也配置JVM的GC日志分割策略。這樣一來(lái),既保證了 GC 文件不會(huì)被覆蓋,又保證了單個(gè) GC 文件的大小不會(huì)過(guò)大,完美!

          最終得到的日志文件名會(huì)像這個(gè)樣子:

          • gc-2021-03-29_20-41-47.log.0
          • gc-2021-03-29_20-41-47.log.1
          • gc-2021-03-29_20-41-47.log.2
          • gc-2021-03-29_20-41-47.log.3
          • ....

          最佳實(shí)踐 - 完整參數(shù)

          # 必備
          -XX:+PrintGCDetails 
          -XX:+PrintGCDateStamps 
          -XX:+PrintTenuringDistribution 
          -XX:+PrintHeapAtGC 
          -XX:+PrintReferenceGC 
          -XX:+PrintGCApplicationStoppedTime

          # 可選
          -XX:+PrintSafepointStatistics 
          -XX:PrintSafepointStatisticsCount=1

          # GC日志輸出的文件路徑
          -Xloggc:/path/to/gc-%t.log
          # 開(kāi)啟日志文件分割
          -XX:+UseGCLogFileRotation 
          # 最多分割幾個(gè)文件,超過(guò)之后從頭文件開(kāi)始寫(xiě)
          -XX:NumberOfGCLogFiles=14
          # 每個(gè)文件上限大小,超過(guò)就觸發(fā)分割
          -XX:GCLogFileSize=100M

          來(lái)源:juejin.cn/post/6949885566536138783

          END -

          「技術(shù)分享」某種程度上,是讓作者和讀者,不那么孤獨(dú)的東西。歡迎關(guān)注我的微信公眾號(hào):Kirito的技術(shù)分享」


          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本三级在线网站 | 熟妇人妻中文字幕无码老熟妇 | 天堂网综合 | 国产一区亚洲天堂 | 日本久久一区 |