JVM 常用工具和優(yōu)化
JDK 自帶的
jconsole
jvisualvm
三方的工具
arthas
調(diào)優(yōu)關(guān)注點(內(nèi)存耻台、GC):
內(nèi)存
- MAT
- XElephant
- 在線:perfma
GC
拿到GC日志,分析GC日志(吞吐量,停頓時間彭雾,垃圾回收次數(shù)揪利;這三個是評判垃圾收集器好壞的標(biāo)準(zhǔn))
- 本地:GCViewer
- 在線:gceasy.io
在什么情況下調(diào)優(yōu)
體現(xiàn)系統(tǒng)性能的參考因素
首先我們需要知道系統(tǒng)當(dāng)前的運行狀況,也就是系統(tǒng)的性能好壞,才能判斷是否需要調(diào)優(yōu)幸斥。如果系統(tǒng)的響應(yīng)時間很短,計算機(jī)的資源使用也很低咬扇,那我們做系統(tǒng)調(diào)優(yōu)就完全是為了調(diào)優(yōu)而調(diào)優(yōu)甲葬。那么衡量系統(tǒng)性能的指標(biāo)到底有哪些呢?
- 響應(yīng)時間:響應(yīng)時間是衡量系統(tǒng)性能的重要指標(biāo)之一懈贺,響應(yīng)時間越短经窖,性能越好,一般一個接口的響應(yīng)時間是在毫秒級梭灿。響應(yīng)時間還包括數(shù)據(jù)庫響應(yīng)時間画侣、服務(wù)端響應(yīng)時間、網(wǎng)絡(luò)響應(yīng)時間堡妒、客戶端響應(yīng)時間配乱。
- TPS:指系統(tǒng)接口的 TPS(每秒事務(wù)處理量),因為 TPS 體現(xiàn)了接口的性能,TPS 越大搬泥,性能越好桑寨。在系統(tǒng)中,吞吐量分為兩種:磁盤吞吐量和網(wǎng)絡(luò)吞吐量忿檩。
- 計算機(jī)資源分配使用率:通常由 CPU 占用率尉尾、內(nèi)存使用率、磁盤 I/O燥透、網(wǎng)絡(luò) I/O 來表示資源使用率沙咏。這幾個參數(shù)好比一個木桶,如果其中任何一塊木板出現(xiàn)短板兽掰,任何一項分配不合理芭碍,對整個系統(tǒng)性能的影響都是毀滅性的。
JVM 調(diào)優(yōu)都做些什么孽尽?
具體來說 JVM 調(diào)優(yōu)需要包括兩方面:合理地設(shè)置 JVM 的內(nèi)存空間和選擇合適的垃圾回收器窖壕。
- 內(nèi)存空間的分配設(shè)置:JVM 內(nèi)存分配不合理帶來的性能表現(xiàn)并不會像內(nèi)存溢出問題這么突出,最直接的表現(xiàn)就是頻繁的 GC杉女,這會導(dǎo)致上下文切換等性能問題瞻讽,從而降低系統(tǒng)的吞吐量、增加系統(tǒng)的響應(yīng)時間熏挎。具體的實現(xiàn)包括調(diào)整堆內(nèi)存空間減少 Full GC速勇、調(diào)整年輕代減少 MinorGC、設(shè)置合理的 Eden 和 Survivor 區(qū)的比例坎拐。
- 選擇合適的垃圾回收器:垃圾回收主要是指堆和方法區(qū)的回收烦磁,堆中的回收主要是對象的回收,方法區(qū)的回收主要是廢棄常量和無用的類的回收哼勇。垃圾收集器的種類很多都伪,不同的場景有不同的選擇。對于每次操作的響應(yīng)時間要求比較高的积担,我們可以選擇響應(yīng)速度較快的 GC回收器陨晶,比如 CMS 回收器和 G1 回收器;而對系統(tǒng)吞吐量有較高要求時帝璧,就可以選擇 Parallel Scavenge 回收器來提高系統(tǒng)的吞吐量先誉。
是否需要 JVM 調(diào)優(yōu)?
一般項目肯定是不需要進(jìn)行 JVM 調(diào)優(yōu)的的烁,因為 JVM 本身就是為這種低延時褐耳、高并發(fā)、大吞吐的服務(wù)設(shè)計和優(yōu)化的渴庆,我們很少需要去改變什么铃芦。所以买雾,我們往往更偏重于應(yīng)用服務(wù)本身的調(diào)優(yōu)。
在一些應(yīng)用中杨帽,比如大數(shù)據(jù)計算引擎漓穿,是一種非常極端的 JVM 應(yīng)用,對延時的要求并不高注盈,但對吞吐量要求很高晃危,會有大量的短生命周期對象產(chǎn)生,同時也有大量的對象生存時間非常久老客,我們就需要對特定的一些 JVM 參數(shù)進(jìn)行修改僚饭。
再比如生產(chǎn)環(huán)境中出現(xiàn)內(nèi)存溢出,我們需要判斷是由于大峰值下沒有限流胧砰,瞬間創(chuàng)建大量對象而導(dǎo)致的內(nèi)存溢出鳍鸵,還是是由于內(nèi)存泄漏而導(dǎo)致的內(nèi)存溢出。對于內(nèi)存泄漏導(dǎo)致的尉间,這種問題就是程序的 Bug偿乖,我們需要及時找到問題代碼進(jìn)行修改,而不是調(diào)整 JVM哲嘲。
JVM 在很大程度上減輕了 Java 開發(fā)人員投入到對象生命周期管理的精力贪薪。在使用對象的時候,JVM 會自動分配內(nèi)存給對象眠副,在不使用的時候画切,垃圾回收器會自動回收對象,釋放占用的內(nèi)存囱怕。所以一般情況下我們是不需要調(diào)優(yōu)的霍弹。當(dāng)然事無絕對,某些特殊場景就需要我們進(jìn)行參數(shù)調(diào)整娃弓,但調(diào)整的前提一定是你對 JVM 的運行原理非常熟悉才行典格。
JVM錯誤排查與解決案例
JVM性能優(yōu)化到底從發(fā)現(xiàn)到解決的歷程:發(fā)現(xiàn)問題-排查問題-解決問題
案列一:
發(fā)現(xiàn)問題:JVM日志 gc.log 文件,通過JVM工具(比如:gceasy)查看并發(fā)現(xiàn)問題忘闻;比如GC的次數(shù)過多钝计;可以通過工具查看到GC次數(shù)【新生代和老年代分別的GC次數(shù)】恋博。GC頻繁:如何判斷GC頻繁呢齐佳?有個參照【比如服務(wù)剛上線GC5次,運行一段時間后10次债沮,在之后30次炼吴,在之后50次,依次類推】
排查問題:打印出JVM GC日志疫衩,查看minorGC(新生代GC)或者majorGC(老年代GC)
解決問題:適當(dāng)增加堆內(nèi)存空間硅蹦,或者選擇合適的垃圾收集器
案例二:
發(fā)現(xiàn)問題:OOM
排查問題:在JVM參數(shù)中配置,如果發(fā)生了OOM錯誤時自動dump下相關(guān)的.hprof文件,對該文件通過工具(比如MAT或者在線的perfma)進(jìn)行分析童芹;分析之后當(dāng)找到占用內(nèi)存比較大的對象對應(yīng)的線程的業(yè)務(wù)代碼(可能是程序死循環(huán)涮瞻,或者后端程序并發(fā)量比較大)
解決問題:如果是并發(fā)量比較大,就減少對后端程序的訪問假褪;通過Nginx增加機(jī)器署咽,負(fù)載均衡,權(quán)重比例
案例三
發(fā)現(xiàn)問題:CPU負(fù)載過高
排查問題:命令:top jps jinfo jstat jmap 等這些命令靈活配合使用查看生音;可能是服務(wù)程序處理壓力過大
解決問題:具體看情況而論宁否,可以集群部署、或者通過中間件(MQ缀遍、Kafka等)實現(xiàn)異步請求
案例四
發(fā)現(xiàn)問題:死鎖
排查問題:可以通過 jstack 命令去查看相關(guān)線程鎖的信息
解決問題:找到對應(yīng)的業(yè)務(wù)代碼慕匠,進(jìn)行修改;或者使用zk域醇、redis實現(xiàn)分布式鎖
案例五
發(fā)現(xiàn)問題:線程池不夠用了
排查問題:通過JDK的工具 jconcole jvisualvm 查看哪些線程得不到釋放的
解決問題:適當(dāng)?shù)膶蠖舜a優(yōu)化台谊,及時釋放資源、合理的設(shè)置線程池中的參數(shù)(大衅┲俊)