<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 調優(yōu)一個月,性能提升了 400 倍!

          共 4402字,需瀏覽 9分鐘

           ·

          2021-07-13 20:27

          點擊關注公眾號,Java干貨及時送達

          通過這一個多月的努力,將 FullGC 從 40 次/天優(yōu)化到近 10 天才觸發(fā)一次,而且 YoungGC 的時間也減少了一半以上,這么大的優(yōu)化,有必要記錄一下中間的調優(yōu)過程。

          對于JVM垃圾回收,之前一直都是處于理論階段,就知道新生代,老年代的晉升關系,這些知識僅夠應付面試使用的。前一段時間,線上服務器的FullGC非常頻繁,平均一天40多次,而且隔幾天就有服務器自動重啟了,這表明的服務器的狀態(tài)已經非常不正常了,得到這么好的機會,當然要主動請求進行調優(yōu)了。未調優(yōu)前的服務器GC數(shù)據,F(xiàn)ullGC非常頻繁。

          首先服務器的配置非常一般(2核4G),總共4臺服務器集群。每臺服務器的FullGC次數(shù)和時間基本差不多。其中JVM幾個核心的啟動參數(shù)為:

          -Xms1000M -Xmx1800M -Xmn350M -Xss300K -XX:+DisableExplicitGC -XX:SurvivorRatio=4 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC

          -Xmx1800M:設置JVM最大可用內存為1800M。-Xms1000m:設置JVM初始化內存為1000m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內存。-Xmn350M:設置年輕代大小為350M。整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。

          此值對系統(tǒng)性能影響較大,Sun官方推薦配置為整個堆的3/8。-Xss300K:設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統(tǒng)對一個進程內的線程數(shù)還是有限制的,不能無限生成,經驗值在3000~5000左右。

          第一次優(yōu)化

          一看參數(shù),馬上覺得新生代為什么這么小,這么小的話怎么提高吞吐量,而且會導致YoungGC的頻繁觸發(fā),如上如的新生代收集就耗時830s。初始化堆內存沒有和最大堆內存一致,查閱了各種資料都是推薦這兩個值設置一樣的,可以防止在每次GC后進行內存重新分配。基于前面的知識,于是進行了第一次的線上調優(yōu):提升新生代大小,將初始化堆內存設置為最大內存

          -Xmn350M -> -Xmn800M -XX:SurvivorRatio=4 -> -XX:SurvivorRatio=8 -Xms1000m ->-Xms1800m

          將SurvivorRatio修改為8的本意是想讓垃圾在新生代時盡可能的多被回收掉。就這樣將配置部署到線上兩臺服務器(prod,prod2另外兩臺不變方便對比)上后,運行了5天后,觀察GC結果,YoungGC減少了一半以上的次數(shù),時間減少了400s,但是FullGC的平均次數(shù)增加了41次。YoungGC基本符合預期設想,但是這個FullGC就完全不行了。

          就這樣第一次優(yōu)化宣告失敗。

          第二次優(yōu)化

          在優(yōu)化的過程中,我們的主管發(fā)現(xiàn)了有個對象T在內存中有一萬多個實例,而且這些實例占據了將近20M的內存。于是根據這個bean對象的使用,在項目中找到了原因:匿名內部類引用導致的,偽代碼如下:

          public void doSmthing(T t){
           redis.addListener(new Listener(){
            public void onTimeout(){
             if(t.success()){
              //執(zhí)行操作
             }
            }
           });
          }

          由于listener在回調后不會進行釋放而且回調是個超時的操作,當某個事件超過了設定的時間(1分鐘)后才會進行回調,這樣就導致了T這個對象始終無法回收,所以內存中會存在這么多對象實例。通過上述的例子發(fā)現(xiàn)了存在內存泄漏后,首先對程序中的error log文件進行排查,首先先解決掉所有的error事件。然后再次發(fā)布后,GC操作還是基本不變,雖然解決了一點內存泄漏問題,但是可以說明沒有解決根本原因,服務器還是繼續(xù)莫名的重啟。

          內存泄漏調查

          經過了第一次的調優(yōu)后發(fā)現(xiàn)內存泄漏的問題,于是大家都開始將進行內存泄漏的調查,首先排查代碼,不過這種效率是蠻低的,基本沒發(fā)現(xiàn)問題。于是在線上不是很繁忙的時候繼續(xù)進行dump內存,終于抓到了一個大對象。

          這個對象竟然有4W多個,而且都是清一色的ByteArrowRow對象,可以確認這些數(shù)據是數(shù)據庫查詢或者插入時產生的了。于是又進行一輪代碼分析,在代碼分析的過程中,通過運維的同事發(fā)現(xiàn)了在一天的某個時候入口流量翻了好幾倍,竟然高達83MB/s。

          經過一番確認,目前完全沒有這么大的業(yè)務量,而且也不存在文件上傳的功能。咨詢了云服務器客服也說明完全是正常的流量,可以排除攻擊的可能。另外,《46 張 PPT 弄懂 JVM 性能調優(yōu)》有必要學習下。

          就在我還在調查入口流量的問題時,另外一個同事找到了根本的原因,原來是在某個條件下,會查詢表中所有未處理的指定數(shù)據,但是由于查詢的時候where條件中少加了模塊這個條件,導致查詢出的數(shù)量達40多萬條,而且通過log查看當時的請求和數(shù)據,可以判斷這個邏輯確實是已經執(zhí)行了的,dump出的內存中只有4W多個對象,這個是因為dump時候剛好查詢出了這么多個,剩下的還在傳輸中導致的。而且這也能非常好的解釋了為什么服務器會自動重啟的原因

          點擊關注公眾號,Java干貨及時送達

          解決了這個問題后,線上服務器運行完全正常了,使用未調優(yōu)前的參數(shù),運行了3天左右FullGC只有5次:

          第三次調優(yōu)

          內存泄漏的問題已經解決了,剩下的就可以繼續(xù)調優(yōu)了,經過查看GC log,發(fā)現(xiàn)前三次GullGC時,老年代占據的內存還不足30%,卻發(fā)生了FullGC。另外,微信搜索Java技術棧,在后臺發(fā)送:JVM46,可以獲取一份完整的 JVM 調優(yōu)指南。

          于是進行各種資料的調查,在:https://blog.csdn.net/zjwstz/article/details/77478054 博客中非常清晰明了的說明metaspace導致FullGC的情況,服務器默認的metaspace是21M,在GC log中看到了最大的時候metaspace占據了200M左右,于是進行如下調優(yōu),以下分別為prod1和prod2的修改參數(shù),prod3,prod4保持不變。

          Java 核心技術教程和示例源碼看這里:https://github.com/javastacks/javastack

          -Xmn350M -> -Xmn800M -Xms1000M ->1800M -XX:MetaspaceSize=200M -XX:CMSInitiatingOccupancyFraction=75

          -Xmn350M -> -Xmn600M -Xms1000M ->1800M -XX:MetaspaceSize=200M -XX:CMSInitiatingOccupancyFraction=75

          prod1和2只是新生代大小不一樣而已,其他的都一致。到線上運行了10天左右,進行對比:prod1:

          prod2:

          prod3:

          prod4:

          對比來說,1,2兩臺服務器FullGC遠遠低于3,4兩臺,而且1,2兩臺服務器的YounGC對比3,4也減少了一半左右,而且第一臺服務器效率更為明顯,除了YoungGC次數(shù)減少,而且吞吐量比多運行了一天的3,4兩臺的都要多(通過線程啟動數(shù)量),說明prod1的吞吐量提升尤為明顯。通過GC的次數(shù)和GC的時間,本次優(yōu)化宣告成功,且prod1的配置更優(yōu),極大提升了服務器的吞吐量和降低了GC一半以上的時間。

          prod1中的唯一一次FullGC:

          通過GC log上也沒看出原因,老年代在cms remark的時候只占據了660M左右,這個應該還不到觸發(fā)FullGC的條件,而且通過前幾次的YoungGC調查,也排除了晉升了大內存對象的可能,通過metaspace的大小,也沒有達到GC的條件。這個還需要繼續(xù)調查,有知道的歡迎指出下,這里先行謝過了。

          總結

          通過這一個多月的調優(yōu)總結出以下幾點:

          • FullGC一天超過一次肯定就不正常了
          • 發(fā)現(xiàn)FullGC頻繁的時候優(yōu)先調查內存泄漏問題
          • 內存泄漏解決后,jvm可以調優(yōu)的空間就比較少了,作為學習還可以,否則不要投入太多的時間
          • 如果發(fā)現(xiàn)CPU持續(xù)偏高,排除代碼問題后可以找運維咨詢下云服務器客服,這次調查過程中就發(fā)現(xiàn)CPU 100%是由于服務器問題導致的,進行服務器遷移后就正常了。
          • 數(shù)據查詢的時候也是算作服務器的入口流量的,如果訪問業(yè)務沒有這么大量,而且沒有攻擊的問題的話可以往數(shù)據庫方面調查
          • 有必要時常關注服務器的GC,可以及早發(fā)現(xiàn)問題

          以上是最近一個多月JVM調優(yōu)的過程與總結,如有錯誤之處歡迎指正。另外,關注公眾號Java技術棧,在后臺回復:面試,可以獲取我整理的 Java/ JVM 系列面試題和答案,非常齊全。

          原文鏈接:https://blog.csdn.net/cml_blog/article/details/81057966

          版權聲明:本文為CSDN博主「cmlbeliever」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。






          關注Java技術棧看更多干貨



          獲取 Spring Boot 實戰(zhà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>
                  一区二区三区免费无码 | 北条麻妃在线观看免费91 | 一道本高清无码视频 | 五楼自拍| 国产成人主播 |