visualvm工具遠程對linux服務器上的JVM虛擬機進行監控與調優


文/朱季謙

 

最近做了一些JVM監控與調優的事情,算是第一次實踐,還比較陌生,故而先把這一次經驗簡單記下筆記,這樣,對后面學習調優方面時,不至於又想不起來了。


本文檔主要總結在window本地環境遠程對linux服務斷的JVM虛擬機進行監控與調優的方法。

visualvm工具是JDK自帶的,在java安裝目錄下可以找到:C:\Program Files\Java\jdk1.8.0_77\bin

打開visualvm工具,右擊遠程,添加遠程主機——

在彈出框上的主機名處,填寫需要連接的服務器IP——

添加成功后,右邊框就出現了以下圖標——

這時,右擊“42.194.xx.xx”,會看到,有兩種遠程連接方式,一個是JMX,一個是jstatd。

這里主要分享是以jstatd模式。在以jstatd模式連接前,需要在監控的遠程服務端啟動jstatd,啟動步驟如下——

  1. 找到服務端jdk的bin目錄,新建jstatd.all.policy文件

    [root@VM-16-4-centos bin]# whereis java java: /usr/bin/java [root@VM-16-4-centos bin]# cd /usr/bin/ [root@VM-16-4-centos bin]# vim jstatd.all.policy

    將以下內容復制到jstatd.all.policy文件里——

    grant codebase "file:${java.home}/../lib/tools.jar" {
      permission java.security.AllPermission;
    };

    保存,設置權限——

    [root@VM-16-4-centos bin]# chmod 777 jstatd.all.policy

    設置成功——

  2. 在監控的遠程服務端啟動jstatd

    執行 jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=42.194.xxx.xx &

    注:42.194.xxx.xx 是我個人騰訊雲機器IP。

    [root@VM-16-4-centos bin]#  jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=42.194.xxx.xx & [1] 52056

    這時,觀察visualvm工具右邊欄菜單,可以看到遠程連接的服務端已經自動連接上jstatd,這就意味着,可以在本地通過遠程jstatd來監控開發服務器上的jvm信息了,從而進行jvm調優監控等操作。

    點擊其中一個進程biz-0.0.1-SNZPSHOT.jar,就可以進入到對應的監控台——

    visualvm控制台有概述、監視、抽樣器等菜單,同時,可以裝入插件擴展功能——

    • 概述

    可以看到jvm參數、系統屬性、jdk版本與安裝路徑等信息;

    設置的jvm參數,這里新生代分配了最小堆空間是256m,最大堆空間是256m,新生代128m,元空間是128m,堆=新生代+老年代,不包括永久代(方法區),這就意味着,這配置當中的老年代=256m。

    -Xms256M -Xmx256M -Xmn128M -XX:PermSize=128M -XX:MaxPermSize=256M

    這些都是指定JVM參數運行對應的jar進程,除此之外,還有其他參數可做設置。

    • 監視

    監控模塊可以實時看到進程所在的堆、元空間、類及線程的報表數據監控,其中,堆和元空間的報表對調優可以起到很有用的幫助。

除了visualvm自帶的功能外,我們需要裝入一個實時監控GC的插件visualgc,這個插件很方便對JVM做監控與調優。

考慮到visualgc插件通過官網下載很慢,我已經保存在網盤當中,可直接通過網盤進行下載——

鏈接:https://pan.baidu.com/s/17TSf0ZdFtMdfog6xzbj3ZQ 提取碼:el6c

插件裝載方式,右擊工具欄,選擇插件——

彈出框后,點“已下載”按鈕,再點擊“添加插件”將需要安裝的visualgc插件添加進來——

安裝成功后,重啟一下visualvm,就可以看到菜單欄上多出一個Visual GC插件——

Visual gc 工具分成布局分成三部分,可在右上角對應方框里勾選【Space】【Graphs】【Histogram】,它們各自的作用——

  • 可視化GC窗口(space)

  • 圖形統計窗口(Graphs)

  • 幸存者年齡直方圖窗口(Histogram)

下面分別介紹各自窗口與其顯示的數字表示——

  1. 可視化GC窗口(space)

    VisualGC窗口是最左的窗口,分成三條垂直柱體,在JDK1.8版本中,分別代表metaSpace元空間、Old老年代、新生代,其中新生代又划分成 Eden 區, S0 區, S1區三部分。柱體里顏色部分代表占用的空間,空白部分表示剩余空間。監控項目的堆進程時,這些代表顏色的地方都是動態變化的。

  2. 圖形統計窗口(Graphs)

    圖形窗口顯示各種統計值隨時間的變化。

    一、Compile Time

    顯示將Java字節代碼編譯為本機代碼所花費的時間量。窄脈沖表示持續時間相對較短,寬脈沖表示持續時間較長。

    • 編譯任務的數量5508;

    • 累計編譯時間27.721s。

    二、Class Loader Time

    此面板顯示在類加載和卸載活動中花費的時間量。窄脈沖表示持續時間相對較短,寬脈沖表示持續時間較長。

    • 加載的類數量:11337;

    • 卸載的類的數量:0

    • 累計的類加載時間:15.589s

    三、GC Time

    此面板顯示垃圾收集活動所花費的時間量。窄脈沖表示持續時間相對較短,寬脈沖表示持續時間較長。

    • 執行GC垃圾回收總次數:9次(9 collections代表自監視以來執行9次GC,其中,包括新生代的Minor GC和老年代的Full Gc)

    • 累計的GC時間:888.929ms;

    • 若JVM維護hotspot.gc.cause和hotspot.gc.last_cause計數器,則gc事件的原因將出現在last Cause中;

    四、Eden Space

    此面板顯示Eden空間隨時間的利用情況。它是年輕代的三個空間之一,另外兩個分別是S0、S1。空間的當前容量可以根據收集器策略動態更改,即通過修改--Xmn參數,會改變其大小。

    標題欄第一個參數代表最大容量,第二個參數代表當前容量,后跟當前占用空間。此外,還包含了年輕代GC事件數量和GC累計時間。

    • Eden Space最大可分配空間:102.500M;

    • Eden Space當前已分配空間:102.500M;

    • Eden Space當前占用空間:54.523M(當積累的占用空間超過102.500M,就會在Eden Space發生一次Minor GC)

    • Minor GC次數:6次

    • Minor GC花費時間:286.621ms

    五、Survivor 0 and Survivor 1

    HotSpot JVM把年輕代分為了三部分:1個Eden區和2個Survivor區(分別叫from和to),默認大小比例為Eden:Survivor0:Survivor1=8:1:1的。 新創建的非大對象,會存放在Eden區和一個作為from的Survivor區,當發生一次Minor GC時,就會將Eden區和作為from的Survivor區內仍存活的對象,復制到另一個作為to的Survivor區,然后清理掉原來Eden區和作為from的Survivor區內對象。因此,S0 和 S1 之間至少有一個肯定是空閑的。

    • Survivor 0區最大分配容量:12.750M;

    • Survivor 0區當前已分配容量:12.750M;

    • Survivor 0區當前占用容量:0M;

    五、Old Gen

    面板顯示老年代隨着時間推移的利用情況。

    • Old Gen 最大分配空間128M;

    • Old Gen 已分配空間128M;

    • Old Gen 當前占用空間38.06M;

    • Old Gen 發生的GC次數:3次;

    • Old Gen 發生的GC花費時間:602.309ms;

    六、Perm Gen

    標題欄在括號中顯示空間的名稱及其最大容量和當前容量,后跟空間的當前占用大小。

    visual VM工具的相關功能使用主要就介紹那么多,下面就介紹一下入門調優的案例,小白都能看懂的。

    假如某天你觀察到使用visual VM工具的Visual GC插件觀察到以下的圖表——新生代Eden區已經發生了8168次Minor GC,耗時39.754s,另外老年代也發生了24次GC,耗時5.124s。可見,該JVM參數設置得極不合理,導致已經過於頻繁發生Minor GC。

那么,我們該如何調優進行設置呢?

JVM調優無外乎就是對相關參數進行設置,這里,我們先做一些最簡單的參數,好讓小白也能理解,那么,就暫時先對-Xms、-Xmx、-Xmn參數設置。

截圖中,可以看到新生代中的Eden區頻繁發生Minor GC,原因之一是分配的空間過小,目前是204.875M,導致當前占用空間經常超過204.875M,進而發生GC。若要分析是哪些代碼頻繁創建對象,還得進一步通過dump等方式進行分析,這里暫時不展開。

解決該Eden區其中一個思路是,提升分配給Eden區的大小。

那么,多大才比較合適呢?

這時,Visual VM的監視欄中的堆監控就派上用場了。可以觀察到藍色模塊高度比較均衡地對應在縱坐標240MB的樣子,也就是說,新創建的對象其占有的大小達到近300MB,而Eden Space+其中一個Survivor才230MB,可見,每次新創建的對象很容易就超過新生代,這就意味着,頻繁發生Minor GC是必然的,從圖的橫坐標可以看出,每30ms內,就發生了2到3次的Minor GC。

為了避免Eden區頻繁發生Minor GC,根據堆監控圖表,可以考慮在設置JVM參數時,適當提升分配給Eden的空間,至少需要在240MB以上,可以考慮先設置到300MB的樣子,看下效果,當然,這是在項目比較平穩運行的情況下來看的,實際生產當中,還需要考慮到高峰時期。

就暫且先設置Eden區為320MB,考慮到Eden:Survivor0:Survivor1=8:1:1比例,也就是8:2,若要分配Eden=320M,那么,可以根據8/2=320/x算出來,x=80,這里的x就是兩個Survivor總大小,即每個Survivor分配40MB,那么,年輕代總共需要分配的大小為(320M+80M)=400M,即-Xmn400m

再來看下老年代,目前老年代發生了24次GC,最大分配空間是256MB,當前最小分配空間是71.48M,可見,還可以適當進行優化。

一般而言,最大分配空間與最小分配空間最好保持一致,這樣避免每次空間不夠時都需自動提升當前分配大小。

可以暫且考慮最大分配空間與當前分配空間都保持在256M,而根據堆=新生代+老年代,不包括永久代(方法區)。在新生代已經分配300MB情況下,若要讓老年代最大與最小分配空間都為256MB,那么,就需要對JVM堆分配400M+256M=656M的空間大小,即設置-Xms656M、-Xmx656M;

元空間暫且可以不考慮進行分配。

根據以上得出的參數,進行設置,然后以設置好的參數進行項目重啟,根據新一輪圖表展示,繼續進行參數優化,循環調試,直到新生代和老年代的GC頻率都保持一個比較平衡的水准。

以上,就是主要介紹了JVM監控與調優工具,同時,簡單說明了一下如何進行參數調優,實際上,還需調試更多JVM相關參數,才能達到優化效果,至於其他的JVM參數調試,本文暫且不展開介紹了。

最后,需要注意一點,本地環境使用jstatd模式遠程連接線上服務端的JVM時,是不能在本地獲取到堆棧信息的,可以手動生成dump文件來分析出現異常的堆棧信息。

一、設置參數在異常發生時自動生成dump文件。

  • -XX:+HeapDumpOnOutOfMemoryError 表示當JVM發生OOM時,自動生成DUMP文件。

  • -XX:HeapDumpPath=存儲文件/目錄 表示生成DUMP文件的路徑

二、手動生成dump分析文件

執行jmap -dump:format=b,file=20210321.dump 7132,其中7132是對應項目的進程PID。

將獲取到的dump文件手動導入到Visual VM工具,就可以分析哪些對象占用內存高了,往往可以分析出哪些對象造成了內存泄露問題。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM