6-JVM常用工具和優化
- 2020 年 5 月 20 日
- 筆記
JVM 常用工具和優化
JDK 自帶的
jconsole
jvisualvm
三方的工具
arthas
調優關注點(記憶體、GC):
記憶體
- MAT
- XElephant
- 在線:perfma
GC
拿到GC日誌,分析GC日誌(吞吐量,停頓時間,垃圾回收次數;這三個是評判垃圾收集器好壞的標準)
- 本地:GCViewer
- 在線:gceasy.io
在什麼情況下調優
體現系統性能的參考因素
首先我們需要知道系統當前的運行狀況,也就是系統的性能好壞,才能判斷是否需要調優。如果系統的響應時間很短,電腦的資源使用也很低,那我們做系統調優就完全是為了調優而調優。那麼衡量系統性能的指標到底有哪些呢?
- 響應時間:響應時間是衡量系統性能的重要指標之一,響應時間越短,性能越好,一般一個介面的響應時間是在毫秒級。響應時間還包括資料庫響應時間、服務端響應時間、網路響應時間、客戶端響應時間。
- TPS:指系統介面的 TPS(每秒事務處理量),因為 TPS 體現了介面的性能,TPS 越大,性能越好。在系統中,吞吐量分為兩種:磁碟吞吐量和網路吞吐量。
- 電腦資源分配使用率:通常由 CPU 佔用率、記憶體使用率、磁碟 I/O、網路 I/O 來表示資源使用率。這幾個參數好比一個木桶,如果其中任何一塊木板出現短板,任何一項分配不合理,對整個系統性能的影響都是毀滅性的。
JVM 調優都做些什麼?
具體來說 JVM 調優需要包括兩方面:合理地設置 JVM 的記憶體空間和選擇合適的垃圾回收器。
- 記憶體空間的分配設置:JVM 記憶體分配不合理帶來的性能表現並不會像記憶體溢出問題這麼突出,最直接的表現就是頻繁的 GC,這會導致上下文切換等性能問題,從而降低系統的吞吐量、增加系統的響應時間。具體的實現包括調整堆記憶體空間減少 Full GC、調整年輕代減少 MinorGC、設置合理的 Eden 和 Survivor 區的比例。
- 選擇合適的垃圾回收器:垃圾回收主要是指堆和方法區的回收,堆中的回收主要是對象的回收,方法區的回收主要是廢棄常量和無用的類的回收。垃圾收集器的種類很多,不同的場景有不同的選擇。對於每次操作的響應時間要求比較高的,我們可以選擇響應速度較快的 GC回收器,比如 CMS 回收器和 G1 回收器;而對系統吞吐量有較高要求時,就可以選擇 Parallel Scavenge 回收器來提高系統的吞吐量。
是否需要 JVM 調優?
一般項目肯定是不需要進行 JVM 調優的,因為 JVM 本身就是為這種低延時、高並發、大吞吐的服務設計和優化的,我們很少需要去改變什麼。所以,我們往往更偏重於應用服務本身的調優。
在一些應用中,比如大數據計算引擎,是一種非常極端的 JVM 應用,對延時的要求並不高,但對吞吐量要求很高,會有大量的短生命周期對象產生,同時也有大量的對象生存時間非常久,我們就需要對特定的一些 JVM 參數進行修改。
再比如生產環境中出現記憶體溢出,我們需要判斷是由於大峰值下沒有限流,瞬間創建大量對象而導致的記憶體溢出,還是是由於記憶體泄漏而導致的記憶體溢出。對於記憶體泄漏導致的,這種問題就是程式的 Bug,我們需要及時找到問題程式碼進行修改,而不是調整 JVM。
JVM 在很大程度上減輕了 Java 開發人員投入到對象生命周期管理的精力。在使用對象的時候,JVM 會自動分配記憶體給對象,在不使用的時候,垃圾回收器會自動回收對象,釋放佔用的記憶體。所以一般情況下我們是不需要調優的。當然事無絕對,某些特殊場景就需要我們進行參數調整,但調整的前提一定是你對 JVM 的運行原理非常熟悉才行。
JVM錯誤排查與解決案例
JVM性能優化到底從發現到解決的歷程:發現問題-排查問題-解決問題
案列一:
發現問題:JVM日誌 gc.log 文件,通過JVM工具(比如:gceasy)查看並發現問題;比如GC的次數過多;可以通過工具查看到GC次數【新生代和老年代分別的GC次數】。GC頻繁:如何判斷GC頻繁呢?有個參照【比如服務剛上線GC5次,運行一段時間後10次,在之後30次,在之後50次,依次類推】
排查問題:列印出JVM GC日誌,查看minorGC(新生代GC)或者majorGC(老年代GC)
解決問題:適當增加堆記憶體空間,或者選擇合適的垃圾收集器
案例二:
發現問題:OOM
排查問題:在JVM參數中配置,如果發生了OOM錯誤時自動dump下相關的.hprof文件,對該文件通過工具(比如MAT或者在線的perfma)進行分析;分析之後當找到佔用記憶體比較大的對象對應的執行緒的業務程式碼(可能是程式死循環,或者後端程式並發量比較大)
解決問題:如果是並發量比較大,就減少對後端程式的訪問;通過Nginx增加機器,負載均衡,權重比例
案例三
發現問題:CPU負載過高
排查問題:命令:top jps jinfo jstat jmap 等這些命令靈活配合使用查看;可能是服務程式處理壓力過大
解決問題:具體看情況而論,可以集群部署、或者通過中間件(MQ、Kafka等)實現非同步請求
案例四
發現問題:死鎖
排查問題:可以通過 jstack 命令去查看相關執行緒鎖的資訊
解決問題:找到對應的業務程式碼,進行修改;或者使用zk、redis實現分散式鎖
案例五
發現問題:執行緒池不夠用了
排查問題:通過JDK的工具 jconcole jvisualvm 查看哪些執行緒得不到釋放的
解決問題:適當的對後端程式碼優化,及時釋放資源、合理的設置執行緒池中的參數(大小)