<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>

          分享一次簡單的 JVM 調(diào)優(yōu),拿去寫在簡歷上

          共 2890字,需瀏覽 6分鐘

           ·

          2022-06-26 10:00


          本文收錄于 www.cswiki.top

          分享篇 JVM 調(diào)優(yōu)的文章,算是入門級別的,對于初學(xué)者來說應(yīng)該算是一個很好的了解調(diào)優(yōu)思路的文章(對于校招就問有無 JVM 調(diào)優(yōu)經(jīng)驗的我只能說一句 sb),原文來自 https://zhenbianshu.github.io,里面有一些句子和圖片等我都重新做了整理和解釋

          背景

          最近對負(fù)責(zé)的項目進(jìn)行了一次性能優(yōu)化,其中包括對 JVM 參數(shù)的調(diào)整,算是進(jìn)行了一次簡單的 JVM 調(diào)優(yōu),JVM 參數(shù)調(diào)整之后,服務(wù)的整體性能有 5% 左右的提升,還算不錯。

          先介紹一下項目的基本情況:

          項目是一個高 QPS(Queries Per Second:每秒查詢率,一臺服務(wù)器每秒能夠響應(yīng)的查詢請求的次數(shù)) 壓力的 web 服務(wù),單機 QPS 一直維持在 1.5K 以上,由于舊機器的”拖累”,配置的堆大小是 8G,其中 Young 區(qū)是 4G,垃圾回收器用的是 parNew + CMS

          舊狀

          首先是查看當(dāng)前 GC 的情況,主要是使用 jstat 查看 GC 的概況,再查看 GC log,分析單次 GC 的詳細(xì)狀況。

          使用 jstat -GCutil pid 1000 每隔一秒打印一次 GC 統(tǒng)計信息。

          參數(shù)說明如下:

          • S0:新生代中 Survivor space 0 區(qū)已使用空間的百分比
          • S1:新生代中 Survivor space 1 區(qū)已使用空間的百分比
          • E:新生代已使用空間的百分比
          • O:老年代已使用空間的百分比
          • P:永久帶已使用空間的百分比
          • YGC:從應(yīng)用程序啟動到當(dāng)前,發(fā)生 Young GC 的次數(shù)
          • YGCT:從應(yīng)用程序啟動到當(dāng)前,Young GC 所用的時間【單位秒】
          • FGC:從應(yīng)用程序啟動到當(dāng)前,發(fā)生 Full GC 的次數(shù)
          • FGCT:從應(yīng)用程序啟動到當(dāng)前,F(xiàn)ull GC 所用的時間
          • GCT:從應(yīng)用程序啟動到當(dāng)前,用于垃圾回收的總時間【單位秒】

          可以看到,單次 GC 平均耗時是 GCT / (YGC + FGC) = 60ms 左右 ,還算可以接受,但 YGC 太過頻繁。

          接著查看 GC log,打印 GC log 需要在 JVM 啟動參數(shù)里添加以下參數(shù):

          • -XX:+PrintGCDateStamps:打印 GC 發(fā)生的時間戳。
          • -XX:+PrintTenuringDistribution:打印 GC 發(fā)生時的分代信息。
          • -XX:+PrintGCApplicationStoppedTime:打印 GC 停頓時長
          • -XX:+PrintGCApplicationConcurrentTime:打印 GC 間隔的服務(wù)運行時長
          • -XX:+PrintGCDetails:打印 GC 詳情,包括 GC 前/內(nèi)存等。
          • -XlogGC:../GClogs/GC.log.date:指定 GC log 的路徑

          看到的 GC log 形如:

          單次 GC 方面并不能直接看出問題,但可以看到 GC 前有很多次約 18ms 左右的停頓

          分析和調(diào)整

          YGC 頻繁

          直接查看 GC log 并不直觀,我們可以借用一些可視化工具來幫助我們分析,GCeasy - https://GCeasy.io/ 是個挺不錯的網(wǎng)站,我們把 GC log 上傳上去后, GCeasy 可以幫助我們生成各個維度的圖表幫助分析。

          查看 GCeasy 生成的報告,發(fā)現(xiàn)我們服務(wù)的 GC 吞吐量是 95% (GC 吞吐量指 GC 所花費的時間和系統(tǒng)總運行時間的比值, 系統(tǒng)總運行時間= 應(yīng)用程序耗時+GC 耗時),它指的是 JVM 運行業(yè)務(wù)代碼的時長占 JVM 總運行時長的比例,這個比例確實有些低了,運行 100 分鐘就有 5 分鐘在執(zhí)行 GC。幸好這些 GC 中絕大多數(shù)都是 YGC,單次時長可控且分布平均,這使得我們服務(wù)還能平穩(wěn)運行。

          解決這個問題要么是減少對象的創(chuàng)建,要么就增大 Young 區(qū)。前者不是一時半會兒都解決的,需要查找代碼里可能有問題的點,分步優(yōu)化。

          而后者雖然改一下配置就行,但以我們對 GC 最直觀的印象來說,增大 Young 區(qū),YGC 的時長也會迅速增大

          其實這點不必太過擔(dān)心,我們知道 YGC 的耗時是由 標(biāo)記 + 復(fù)制 組成的,相對于復(fù)制,標(biāo)記過程是非常快的。而 Young 區(qū)內(nèi)大多數(shù)對象的生命周期都非常短,如果將 Young 區(qū)增大一倍,標(biāo)記的時長會提升一倍,但到 GC 發(fā)生時被標(biāo)記的對象大部分已經(jīng)死亡, 復(fù)制的時長肯定不會提升一倍,所以我們可以放心增大 Young 區(qū)大小。

          由于低內(nèi)存舊機器都被換掉了,我把堆大小從 8 調(diào)整到了 12G,Young 區(qū)從 4 提升為 8G

          分代調(diào)整

          除了 GC 太頻繁之外,GC 后各分代的平均大小也需要調(diào)整。

          我們知道 GC 的提升機制,每次 GC 后,JVM 存活代數(shù)大于 MaxTenuringThreshold 的對象提升到老年代。

          當(dāng)然,JVM 還有動態(tài)年齡計算的規(guī)則:按照年齡從小到大對其所占用的大小進(jìn)行累積,當(dāng)累積的某個年齡大小超過了 survivor 區(qū)的一半時,取這個年齡和 MaxTenuringThreshold 中更小的一個值,作為新的晉升年齡閾值。不過看各代總的內(nèi)存大小,是達(dá)不到 survivor 區(qū)的一半的。

          所以這十五個分代內(nèi)的對象會一直在兩個 Survivor 區(qū)之間來回復(fù)制,再觀察各分代的平均大小,可以看到,四代以上的對象已經(jīng)有一半都會保留到老年區(qū)了,所以可以將這些對象直接提升到老年代,以減少對象在兩個 survivor 區(qū)之間復(fù)制的性能開銷

          所以我把 MaxTenuringThreshold 的值調(diào)整為 4,將存活超過四代的對象直接提升到老年代。

          偏向鎖停頓

          還有一個問題是 GC log 里有很多約 18ms 左右的停頓,有時候連續(xù)有十多條,雖然每次停頓時長不長,但連續(xù)多次累積的時間也非常可觀。

          這個問題其實就是 JDK1.8 之后 JVM 對鎖進(jìn)行了優(yōu)化,添加了偏向鎖的概念,避免了很多不必要的加鎖操作,但偏向鎖一旦遇到鎖競爭,就會進(jìn)行鎖釋放,而鎖釋放操作需要進(jìn)入安全點 safe point,導(dǎo)致 STW。

          解決方式很簡單,JVM 啟動參數(shù)里添加 -XX:-UseBiasedLocking 取消偏向鎖即可 (JDK15 已經(jīng)廢棄偏向鎖了)。

          結(jié)果

          調(diào)整完 JVM 參數(shù)后先是對服務(wù)進(jìn)行壓測,發(fā)現(xiàn)性能確實有提升,也沒有發(fā)生嚴(yán)重的 GC 問題,之后再把調(diào)整好的配置放到線上機器進(jìn)行灰度,同時收集 GC log,再次進(jìn)行分析。

          由于 Young 區(qū)大小翻倍了,所以 YGC 的頻率減半了,GC 的吞量提升到了 97.75%。不過平均 GC 時長略有上升,從 60ms 左右提升到了 66ms,還是挺符合預(yù)期的。

          由于 CMS 在進(jìn)行 GC 時也會清理 Young 區(qū),CMS 的時長也受到了影響,CMS 的最終標(biāo)記和并發(fā)清理階段耗時增加了,也比較正常。

          另外我還統(tǒng)計了對業(yè)務(wù)的影響,之前因為 GC 導(dǎo)致超時的請求大大減少了。


          心之所向,素履以往,我是小牛肉,回復(fù)『春秋招』我拉你進(jìn)春秋招交流群

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  蜜桃视频在线入口www | 91久久免费 | 亚洲一级二级无码 | 女人一级片看片 | 亚洲高清中文视频 |