JVM监控及诊断工具-命令行篇一
1 jps
基本概述
jps(java process status),用于查看正在運行的java虛擬機進程,會顯示指定系統內所有的HotSpot虛擬機進程(查看虛擬機進程信息)。這里說明一下,對于本地虛擬機進程來說,進程的本地虛擬機ID與操作系統的進程ID是一致的且是唯一的。
初步測試
例如簡單寫一段程序:
public class ScannerTest {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String info = scanner.next();} }然后這里使用Windows的命令行窗口,輸入jps,就會顯示我們剛啟動的程序的信息:
以上的信息看起來比較簡單,所展示的信息也不是很全面,為了更好的輸出相關的信息,我們接下來看一下jps的語法。
基本語法
jps的基本語法如下:
jps [options] [hostid]當然我們還可以追加參數來輸出一些額外的信息,另外我們也可以在命令行窗口輸入jps -help看來查看對應的語法:
接下里說一下各個參數的含義,對于options,有不同的操作:
- -q:僅僅顯示LVMID(local virtual machine id),即本地虛擬機唯一id,不顯示主類的名稱等;
- -l:輸出應用程序主類的全類名或如果進程執行的jar包,則輸出jar完整路徑
- -m:輸出虛擬機進程啟動時傳遞給主類main()的參數
- -v:列出虛擬機進程啟動時的JVM參數,比如-Xms20m,-Xmx50m。
我們接下來實際操作一下。使用jps -q,則只會顯示對應的進程id:
使用jps -l,則顯示對用進程的完成路徑:
使用jps -m,發現信息比較多,我們將其輸出到一個文件中進行查看,發現也沒有什么特別的。
我們在IEDA中給入口函數增加輸入參數likangmin,然后在重新看一下。
輸出發現輸出了對應的參數:
使用jps -v,顯示jvm配置的虛擬機參數,我們打開IDEA的Configuration,配置一下信息:
表示設置jvm虛擬機堆內存大小最大和最小都是100m,然后我們使用jps -v,則可以查看到配置的信息:
當然我們還可以將這些信息組合使用,例如jps -lv,只不過可能信息量比較大,閱讀起來不太方便,這里就不做演示,大家有興趣可以自己輸入命令行查看。需要注意一點-q是獨立使用的。還有一點是如果某java進程關閉了默認開啟的UsePerfData參數(即使用參數-XX:-UsePerfData),那么jps命令將無法探知該java進程。
再重新啟動查看,發現已經找不到我們運行的進程了,此參數默認是開啟的。
option說完,還有hostid, 支持的語法有< hostname>[: < port>],可以支持遠程連接查看遠程機器的參數信息,如果想要進行遠程連接,需要安裝jstatd。對于具有更嚴格的安全實踐的網絡場所而言,可能使用一個自定義的策略文件來顯示對特定的可信主機或者網絡的訪問,盡管這種技術容易受到IP地址欺詐攻擊。如果安全問題無法使用一個定制的策略文件來處理,那么最安全的操作還是不運行jstatd服務器,而是在本地使用jstat和jps工具。
2 jstat
基本概述
jstat(JVM statistic monitoring tool),用于監視虛擬機各種運行狀態信息的命令行工具,它可以顯示本地或者遠程虛擬機進程中的類裝載,內存,垃圾回收,JIT編譯等運行數據。在沒有GUI圖形界面,只提供了純文本控制臺環境的服務器上,它將是運行期定位虛擬機性能問題的首選工具,常用于檢測垃圾回收問題以及內存泄露問題。
基本語法
使用jstat -help查看一下jstat的基本語法
基本使用語法 jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] 查看命令相關參數: jstat -h或jstat -help選項option可以由以下值構成:
- 類裝載相關
- -class :顯示ClassLoader的相關信息,包括類的裝載和卸載數量,總空間,類裝載所消耗的實踐等
- 垃圾回收相關
- -gc :顯示于GC相關的堆信息,包括Eden區,兩個Survivor區,老年代,永久代等的容量,已用空間,GC時間合計等信息;
- -gccapacity :顯示內容與 -gc 基本相同,但是輸出主要關注Java堆各個區域使用到的最大,最小空間;
- -gcutil :顯示內同與 -gc 基本相同,但輸出主要關注已使用空間占總空間的百分比;
- -gccause :與 -gcutil功能一樣,但是會額外輸出導致最后一次或者當前正在發生的GC產生的原因;
- -gcnew :顯示新生代GC的狀況;
- -gcnewcapacity :顯示內容與 -gcnew基本相同,輸出主要關注使用到的最大,最小空間;
- -geold :顯示老年代GC狀況。
- JIT相關
- -compiler:顯示JIT編譯器編譯過的方法,耗時等信息;
- -printcompilation :輸出已經被JIT編譯的方法。
我們首先以-class來進行說明,還是上面的例子,程序如下:
public class ScannerTest {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String info = scanner.next();} }然后正常啟動程序,在命令行中輸入jps找到當前進程的id為38340
然后輸入jstat -class 38340,出現以下信息:
這里是最簡單的輸出,我們沒有帶任何參數,以上信息含義如下:
接下來看一下interval和 count這兩個參數:
interval:用于指定輸出統計數據的周期,單位為毫秒,即查詢間隔 count:用于指定查詢的總次數如我們上面的例子中,沒有指定interval和count參數,所以只會打印一次就結束,如果我們想每隔1000毫秒打印一次,則可以輸入命令:jstat -class 38340 1000
以上是每隔一秒打印一次,有助于我們持續監控相關信息,但是因為沒有指定組要輸出的次數,所以會一直輸出下去直到程序結束或者內存溢出,如果我們想打印10次就停止,那我們可以輸入命令:jstat -class 38340 1000 10
輸出打印十次以后就自動停止了。
接下里說一下-t參數,此參數在進程id的前面,在option的后面,可以在輸出統計信息前加上一個Timestamp列,顯示程序的運行時間,單位為秒。我們加入-t看一下輸出的效果:jstat -class -t 38340
再執行一次時間增加:
最后還有一個參數-h,可以在周期性數據輸出時,輸出多少行數據后輸出一個表頭信息,在之前的周期性數據輸出中,是在最開始的地方有把頭的信息:
如果我們想輸出3行就重新打印一次表頭信息,則可以使用參數-h,后面直接跟上行數即可:jstat -class -t -h3 38340 1000 10
簡答參數說完,我們再回到對于其他option的操作,首先說一下跟JIT相關的,還是同樣的例子,我們你輸入jstat -compiler 38340
大家看對應的屬性就能知道是什么意思,表示編譯過的方法的數目以及耗時。繼續使用jstat -printcompilation 38340
表示已經被JIT編譯的方法的數目以及大小等相關信息。
接下來是比較重要的垃圾回收相關的option操作,我們能將相關option再羅列一遍:
- -gc :顯示于GC相關的堆信息,包括Eden區,兩個Survivor區,老年代,永久代等的容量,已用空間,GC時間合計等信息;
- -gccapacity :顯示內容與 -gc 基本相同,但是輸出主要關注Java堆各個區域使用到的最大,最小空間;
- -gcutil :顯示內同與 -gc 基本相同,但輸出主要關注已使用空間占總空間的百分比;
- -gccause :與 -gcutil功能一樣,但是會額外輸出導致最后一次或者當前正在發生的GC產生的原因;
- -gcnew :顯示新生代GC的狀況;
- -gcnewcapacity :顯示內容與 -gcnew基本相同,輸出主要關注使用到的最大,最小空間;
- -geold :顯示老年代GC狀況。
接下里我們直接使用命令行進行操作,輸入jstat -gc 38340
我們對以上參數做一下說明:
大家對照著看一下就可以知道以上輸出表示的含義。以上是沒有進行垃圾回收的情況,接下來我們換一個例子,代碼如下:
代碼比較簡單,我們設置一下jvm相關參數-Xms60m -Xmx60m -XX:SurvivorRatio=8,啟動程序,查看運行程序進程id為49580
然后輸入jstat -gc 49580 1000 10,可以看到對應的垃圾回收的情況。
這里我們可以參數-t,來進行時間的計算。輸入jstat -gc -t 13764 1000 10
從中選取兩條輸出的信息作為對比,兩者的Timesatmp相減為程序運行的總時間,兩者的GCT相減為運行期間垃圾回收的總時間,依據這些信息我們可以得出GC時間占運行時間的比例。如果該比例超過20%,則說明目前堆的壓力比較大,如果該比例超過90%,則說明堆幾乎沒有可用空間,隨時可能拋出OOM。
然后輸入jstat -gcutil 51280 1000 10,可以看到展示信息與上面相似,只不過這里是以百分比的信息進行展示的。
輸入jstat -gccause 45480 1000 10,顯示垃圾回收失敗的原因。
這里補充一點說明,jstat還可以用來判斷是否出現內存泄漏,步驟如下:
3 jinfo
基本概述
jinfo(Configuration Info for Java),查看虛擬機配置參數信息,也可以用于調整虛擬機的配置參數。在很多情況下,Java應用程序不會指定所有的Java虛擬機參數。而此時,開發人員可能不知道某一個具體的Java虛擬機參數的默認值,在這種情況下,可能需要通過查找文檔獲取某個參數的默認值。這個查找過程是非常艱難的,但有了jinfo工具,開發人員可以很方便地找到Java虛擬機參數的當前值。
基本語法
同樣使用-help看一下jinfo的基本語法:
我們將其用法與搭配的參數做一下總結然后再統一的進行實際操作,首先是針對查找的操作:
下面是針對修改的操作:
jinfo -flag [+|-]具體的參數 PID 針對boolean類型 jinfo -flag 具體的參數=具體的參數值 PID 針對非boolean類型當然還有其他的一些拓展指令:
java -XX:+PrintFlagsInitial 查看所有JVM參數啟動的初始值 java -XX:+PrintFlagsFinal 查看所有JVM參數的最終值 java -XX:+PrintCommandLineFlags 查看那些已經被用戶或者JVM設置過的詳細的XX參數的名稱和值接下來我們來進行實際操作看一下每一個指令具體的輸出。還是使用之前的一個例子,代碼如下:
public class ScannerTest {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String info = scanner.next();} }同樣使用JPS獲取進程id為52200,首先我們對查找進行實踐操作。
然后輸入jinfo -sysprops 52200得到如下一些信息,這里我只截取了部分,基本都是可以通過System.getProperties()取得的參數,這里就不做過多說明。
輸入jinfo -flags 52200,查看曾經賦值過的一些參數
在上面有兩個地方需要注意,Non-default表示非默認的,Command line表示通過命令行賦值的。這里輸出的是所有的參數的值,如果我們想看具體的某一個參數的值,則使用jinfo -flag 具體的參數 PID,例如要看是否使用了ParallelGC,則使用命令jinfo -flag UseParallelGC 52200
輸出-XX:+UseParallelGC表示使用的是ParallelGC,再比如看一下最大堆空間的大小,則可以使用jinfo -flag MaxHeapSize 52200就可以得到對應的值。
其他參數也是類似的操作。以上就是查找的相關操作,接下來進行修改操作的實踐。需要說明的是,jinfo并非所有的參數都支持動態修改,它的修改能力是極其有限的,參數只有被標記為manageable的flag可以被實時修改,修改以后立即生效。我們可以使用命令java -XX:+PrintFlagsFinal -version | grep manageable(linux指令)或java -XX:+PrintFlagsInitial | findstr manageable(window命令)查看被標記為manageable的參數:
例如我們修改 PrintGCDetails的值,首先看一下 PrintGCDetails的原先的值,使用指令jinfo -flag PrintGCDetails 52200,說明沒有使用PrintGCDetails。
然后我們使用jinfo -flag +PrintGCDetails 52200進行修改
然后再次查看,已經發生了改變
上面的參數屬于boolean類型,接下來我們修改一個非boolean類型的,例如MaxHeapFreeRatio,使用jinfo -flag MaxHeapFreeRatio 52200看一下原來的值為100
然后我們使用命令jinfo -flag MaxHeapFreeRatio=90 52200進行修改再進行查看發現已經修改成功。
有個問題需要說明的是如果當前進程結束,再重新開啟,那么我們之前修改的數據也會失效。
最后一部分拓展的指令不做過多的說明,畢竟從解釋上就已經很明確表示什么含義了。輸入java -XX:+PrintFlagsFinal 查看所有JVM參數的最終值,下面只截取了部分數據,其中紅色圈出來的表示修改之后的值(重新賦值過),其他的表示默認值沒有進行過修改。其他的也類似,大家有興趣可以使用指令輸出看一下。
總結
以上是生活随笔為你收集整理的JVM监控及诊断工具-命令行篇一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你知道Integer和int的区别吗
- 下一篇: 远程服务器安装docker和docker