6-JVM常用工具和優化

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 查看哪些線程得不到釋放的

解決問題:適當的對後端代碼優化,及時釋放資源、合理的設置線程池中的參數(大小)

趙小胖個人博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章