【JAVA進階架構師指南】之五:JVM效能調優

悟空不敗發表於2020-06-13

前言

  首先給大家說聲對不起,最近屬實太忙了,白天上班,晚上加班,回家還要收拾家裡,基本每天做完所有事兒都是凌晨一兩點了,沒有精力再搞其他的了.
  好了,進入正題,讓我們來聊聊JVM篇最後一個章節----JVM效能調優.童鞋們隨便開啟一個大廠的招聘崗位JD,應該都會有JVM調優相關的描述,其實招聘方不一定要求候選人真的對JVM調優有實際調優經驗,但是至少得有思路,知道應該怎樣進行JVM層面的效能調優,說實話,知道如何進行JVM層面的效能調優的人,在面試中確實是有加分的.
  筆者在公司擔任面試官的時候,經常會看到候選人簡歷描述有JVM效能調優經驗,每當這個時候我都會問候選人一個問題,你是如何進行JVM效能調優的,很多童鞋的回答就是:噢,就是調整一下初始堆大小,新生代大小.這明顯不是筆者想要的答案,因為這根本就不叫JVM效能調優.童鞋們對號入座一下,對JVM調優僅僅是我上述說的那樣的,趕緊改一下簡歷,不要說自己會JVM效能調優.說實話,對JVM進行效能調優是對架構師的要求,甚至我敢說很多架構師都不一定有實際的JVM效能調優經驗.話不多說,讓我們進入正題,我們將從以下幾點來講解如何進行效能調優:

  • JVM效能調優的前提
  • JVM效能調優的預備知識
  • STW現象--Stop-The-World
  • 垃圾回收器的種類
  • 效能調優的目的
  • 如何進行效能調優

JVM效能調優的前提

  所有有經驗的架構師一定會有一個共識,JVM層面的效能調優一定是作為最後的調優手段,在此之前,一定要確保系統其它方面都已經做到了極致,無法再進行調優了,在這個前提下,才會考慮JVM效能調優.這裡的其他方面包括從前端到架構到程式碼層面,我舉一些例子
從瀏覽器/APP角度可進行的優化有:

  • 減少HTTP請求次數.
  • 使用客戶端快取.
  • 瀏覽器啟用壓縮
  • 使用CDN加速
  • 動態資源和靜態資源分離

從系統層面可進行的優化有:

  • 啟用快取,比如redis快取資料
  • 使用叢集
  • 非同步處理,比如引入訊息佇列
  • 對程式碼的優化

  以上列出的每一點,都能單獨拎出來講很久,但是博文篇幅問題,就不細說了,有興趣的童鞋可以自行下去了解,我們只著重說一下程式碼優化,相信大家都知道,業界比較公認的編碼規範是阿里巴巴釋出的<java開發手冊>,裡面的內容都是阿里集團多年來血的教訓積累的精華,阿里集團內部有一個組織專門負責手冊的編寫和推廣,並且在不斷進行優化,最新版釋出到泰山版了(我看的時候還是華山版,哈哈).如果有童鞋還不知道的,我建議去下載下來看一看.另外阿里雲上有<java開發手冊>的考試,如果通過了這個考試,說明你的編碼規範還是不錯的,有興趣的童鞋可以去試一下.
  除此之外,童鞋們還應該瞭解JVM本身為我們悄悄做的各種優化,其中最重要的是JIT編譯器的優化.我舉幾個例子,比如:方法內聯,逃逸分析等.預設情況下,這些都是開啟的,如果不開啟這些功能,JVM效能會下降50%以上.除此之外,還有一些比如:棧上分配,TLAB等優化.這些內容由於平時我們開發中不會用到,是JVM在背後悄悄為我們做了優化,因此可能很多童鞋都不知道,但是如果想成為一個合格的架構師,這些內容都是必須要知道的,畢竟架構師的知識廣度和深度決定了架構師的高度.
  除此之外,效能調優一定是基於效能測試的,空口說進行效能調優的都是耍流氓,只有在經過了實際的效能測試後,我們才知道系統的瓶頸在哪裡,才知道那些方面需要進行調優,如何進行調優.常用的效能測試指標有TPS/QPS/吞吐量.並且預設所有的介面訪問都遵循二八原則(介面每天80%的訪問量集中在20%的時間內).

JVM效能調優的預備知識

  在進行JVM效能調優之前,我們還得了解JVM,比如我前面的幾篇有關JVM的博文,都是需要掌握的,比如JVM記憶體模型,垃圾回收機制等等.另外我們還需要掌握一些進行JVM分析的工具.其實在我們安裝JDK的時候,JDK已經為我們準備了許多有用的效能調優監控工具,我們可以看一下JDK安裝目錄下的bin目錄:
file

  • jps: 主要用來輸出JVM中執行的程式狀態資訊
  • jstack: 主要用來檢視某個Java程式內的執行緒堆疊資訊
  • jmap: 用來檢視堆記憶體使用狀況,一般結合jhat使用
  • jstat: JVM統計監測工具
  • jconsole: 圖形化的統計工具
  • jvisualvm: 比jconsole功能更強的圖形化的監控工具

  另外我們需要知道,當JVM發生OOM異常時,可以使用命令生成一個.hprof字尾的dump檔案,該檔案是某個時間節點的heap的快照,我們可以使用VisualVM來檢視,也可以用第三方提供的一些工具,比如eclipse的MAT來檢視記憶體溢位的原因.

STW現象

  所謂STW現象(Stop-The-World)是指在執行垃圾收集演算法時,Java應用程式的其他所有執行緒(除了垃圾收集執行緒之外的執行緒)都被掛起.此時,系統只允許GC執行緒繼續執行,其他執行緒全部暫停,等待GC執行緒執行完畢後才能繼續執行.這些工作都是由虛擬機器在後臺自動發起和自動完成的,是在使用者不可見的情況下把使用者正常工作的執行緒全部停掉,舉個例子,某個介面平時可能只需要50ms的RT,忽然某次呼叫花費了200ms.因此STW對實時性要求很高的系統來說是難以接受的.

垃圾回收器的種類

  既然有STW現象,那麼有沒有解決方案呢?這就是我們接下來要講的,垃圾回收器的種類,目前為止,JVM一共為我們提供了七種垃圾回收器,其中年輕代有三種,老年代有三種,另外還有一種特殊的G1:
file
file
file

  當然,在更新版本的JDK中還有一種ZGC,為未來垃圾回收器提供了一種趨勢,有興趣的童鞋可以自行了解.

效能調優的目的和具體過程

  有了前面的鋪墊,終於來到了我們最重要的正題:如何進行JVM效能調優?在我看來JVM調優的具體步驟分為如下幾步:

  • 確定調優的目的,選擇合適的GC collector
  • 調整JVM heap的大小
  • 調整young generation在整個JVM heap中所佔的比重.

確定調優的目的,選擇合適的GC collector

  由於每種垃圾回收器的特性並不相同,因此我們需要根據我們的調優目的選擇合適的垃圾回收器,比如,我們需要降低STW的停頓時間,那我們就不能選用序列和並行的垃圾回收器,而應該選用併發的垃圾回收器,即CMS,與之搭配的新生代垃圾回收器就應該選用ParNew.目前一般主流網際網路公司都是用CMS垃圾回收器.

調整JVM heap的大小

  確定了垃圾回收器的型別,就需要調整JVM heap的大小,在這一步的時候,首先我們需要了解JVM相關的一些指令,比如可以在啟動java程式時加上
-XX:+HeapDumpOnOutOfMemoryError,當發生OOM時,JVM會自動為我們生成DUMP檔案
-XX:+PrintGCDetails -Xloggc:D:\gclogger\gc.log -XX:+PrintGCDateStamps 生成GC日誌
-Xms2g -Xmx2g 當然,還應該要根據實際情況設定heap的最大最小值,童鞋們要知道,預設情況下,java程式啟動的最小heap大小為1/64實體記憶體,最大值為1/4實體記憶體,一般要求我們最大最小值保持一致,避免JVM頻繁擴容和縮容導致不必要的效能浪費.

調整young generation在整個JVM heap中所佔的比重.

  確定了heap的大小,還需要確定新生代的比重
–Xmn1500m -XX:MetaspaceSize=150M

  當然,再厲害的架構師也不可能一次就調整得出最佳的JVM配置引數,而是應該多設定幾組不同的值,放到生產環境(或者和生產環境一樣的環境,比如阿里內部有預發環境,和生產環境保持一致)進行效能測試,通過對比結果得出最佳的JVM效能調優引數,完成JVM效能調優.

總結

  讀完了本篇文章,我相信童鞋們應該或多或少會有些收穫.掌握JVM調整的核心步驟:

  • 確定調優的目的,選擇合適的GC collector
  • 調整JVM heap的大小
  • 調整young generation在整個JVM heap中所佔的比重.
      不瞭解如何進行JVM的調優的人,把本文內容好好理解後,能讓面試官刮目相看;瞭解JVM調優,但是條理不清晰的童鞋,可能會對JVM調優有更清晰的認識.總而言之,筆者認為本文是一篇滿滿的乾貨,網上許多講JVM調優的博文,並沒有這麼系統的講解過真正應該如何進行JVM調優.當然筆者能力有限,如文章有錯誤,歡迎指正,畢竟是人就會犯錯.
      PS:一入JVM深似海,從此再也出不來.對JVM有興趣的童鞋,可以鑽研,但是在經驗不足之前,不建議太過深入瞭解JVM,否則會耽誤自己.當然,立志要成為一名牛逼的架構師,這些都是必須要會的.
      本文我們講完了JVM,下一篇開始,讓我們繼續學習JAVA鎖相關的內容.
      如果覺得博主寫的不錯,歡迎關注博主微信公眾號,博主會不定期分享技術乾貨!
    file

本文由部落格一文多發平臺 OpenWrite 釋出!

相關文章