jvm高级特性第4章-虚拟机性能监控与故障处理工具
【4.2】jdk命令行工具
1、jps:虛擬機進程狀況工具;
C:\Users\pacoson>jps -l // 輸出主類名稱 12272 sun.tools.jps.Jps 12736 chapter3.Page93 2808C:\Users\pacoson>jps -v // 查看虛擬機進程啟動時的參數 12736 Page93 -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -Dfile.encoding=UTF-8 2808 -Dosgi.requiredJavaVersion=1.6 -Xms40m -Xmx512m -Dgrails.console.enable.interactive=false -Dgrails.console.enable.terminal=false -Djline.terminal=jline.UnsupportedTerminal -Dgrails.console.class=grails.build.logging.GrailsEclipseConsole 6072 Jps -Dapplication.home=D:\Java\jdk1.8.0_172 -Xms8mC:\Users\pacoson>jps // 列出正在運行的虛擬機進程 12736 Page93 2808 7992 Jps補充:
jps -q 僅輸出本地虛擬機唯一id, LVMID;
jps -m 輸出虛擬機啟動時傳遞給主類的main函數的參數;
jps可以通過rmi 協議查看開啟了rmi服務的遠程虛擬機進程狀態 ;?
2、jstat:虛擬機統計信息監視工具(java statistics monitoring tool)
C:\Users\pacoson>jstat -gcutil 12736 1000 20 // 每隔1000毫秒查看虛擬機12736的內存使用率,共查看20次S0 S1 E O M CCS YGC YGCT FGC FGCT GCT0.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.4210.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.4210.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.4210.00 0.00 52.00 64.89 53.87 54.43 6 0.015 8 0.405 0.421S0=Survivor0, S=Suivivor1, E=Eden區域, O=Old區域, YGC=Young GC=收集年輕代次數=6, YGCT=0.015秒(年輕代收集耗時), FGC=Full GC=老年代收集次數=8, FGCT=Full GC Time=老年代收集耗時=0.421;?
3、jinfo:java配置信息工具: 實時查看和調整虛擬機各項參數;
C:\Users\pacoson>jps // 查看本地java虛擬機id 12736 Page93 11496 Jps 2808C:\Users\pacoson>jinfo -flags //查看虛擬機參數 Usage:jinfo [option] <pid>(to connect to running process)jinfo [option] <executable <core>(to connect to a core file)jinfo [option] [server_id@]<remote server IP or hostname>(to connect to remote debug server)where <option> is one of:-flag <name> to print the value of the named VM flag-flag [+|-]<name> to enable or disable the named VM flag // +啟用/-停用-flag <name>=<value> to set the named VM flag to the given value // 設置參數值-flags to print VM flags-sysprops to print Java system properties<no option> to print both of the above-h | -help to print this help messageC:\Users\pacoson> C:\Users\pacoson>jinfo -flags 12736 Attaching to process ID 12736, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.172-b11 Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=10485760 -XX:OldSize=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC Command line: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -Dfile.encoding=UTF-84、jmap:java內存映像工具,用于生成堆轉儲快照文件,一般稱為heapdump 或 dump文件(堆轉儲快照文件);
使用-XX:+HeapDumpOnOutOfMemoryError參數,可以讓jvm在oom異常出現之后自動生成dump文件;?
jmap在windows平臺下的功能是受限的;?
jmap和jhat連用以查看虛擬機堆轉儲快照如下:
5、jhat:虛擬機堆轉儲快照分析工具;jvm Heap Analysis Tool,與jmap搭配使用;(不推薦使用jhat命令分析dump文件)
推薦的分析堆轉儲快照工具有:VisualVM, Eclipse Memory Analyzer, IBM HeapAnalyzer等工具;
C:\Users\pacoson>jmap -dump:format=b,file=eclipse.bin 12736 // 生成jvm12736的堆轉儲快照文件 Dumping heap to C:\Users\pacoson\eclipse.bin ... File existsC:\Users\pacoson> C:\Users\pacoson>jhat eclipse.bin // 啟用內嵌web服務器分析eclpse.bin 文件(訪問localhost:7000) Reading from eclipse.bin... Dump file created Tue May 07 23:43:59 CST 2019 Snapshot read, resolving... Resolving 7066 objects... Chasing references, expect 1 dots. Eliminating duplicate references. Snapshot resolved. Started HTTP server on port 7000 Server is ready.6、jstack:java堆棧跟蹤工具
jstack=stack trace for java, 用于生成虛擬機當前時刻的線程快照(一般稱為threaddump文件或 javacore文件);
線程快照就是當前虛擬機內每一條線程正在執行的方法堆棧集合,生成線程快照的主要目的是定位線程出現長時間停頓的原因,如線程死鎖,死循環,請求外部資源超時等;
C:\Users\pacoson>jstack -l 12736 // 查看12736進程堆棧信息 2019-05-12 20:55:41 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode):"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x000000001557f000 nid=0x794 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x0000000015505000 nid=0x36e8 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000154fe000 nid=0x3ab4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000154f1000 nid=0x32b4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x0000000015499000 nid=0x16e4 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000015498000 nid=0x578 waiting on condition [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000154ef800 nid=0x5b0 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLELocked ownable synchronizers:- None"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000015480800 nid=0x2c3c in Object.wait() [0x000000001595f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x00000000fec08a78> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)- locked <0x00000000fec08a78> (a java.lang.ref.ReferenceQueue$Lock)at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)Locked ownable synchronizers:- None"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001357d000 nid=0x103c in Object.wait() [0x000000001545f000]java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x00000000fec01158> (a java.lang.ref.Reference$Lock)at java.lang.Object.wait(Object.java:502)at java.lang.ref.Reference.tryHandlePending(Reference.java:191)- locked <0x00000000fec01158> (a java.lang.ref.Reference$Lock)at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)Locked ownable synchronizers:- None"main" #1 prio=5 os_prio=0 tid=0x0000000002f2d800 nid=0x780 waiting on condition [0x0000000002a8f000]java.lang.Thread.State: TIMED_WAITING (sleeping)at java.lang.Thread.sleep(Native Method)at chapter3.Page93.minorGC(Page93.java:24)at chapter3.Page93.main(Page93.java:10)Locked ownable synchronizers:- None"VM Thread" os_prio=2 tid=0x0000000013578000 nid=0x3350 runnable"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002df7800 nid=0x3958 runnable"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002df9000 nid=0x4a7c runnable"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002dfa800 nid=0xcdc runnable"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002dfc000 nid=0x3a2c runnable"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000002dfe800 nid=0x3b30 runnable"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002dff800 nid=0x3a0 runnable"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002e02800 nid=0x2a0 runnable"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002e05000 nid=0x1ed4 runnable"VM Periodic Task Thread" os_prio=2 tid=0x00000000155ae000 nid=0x35e8 waiting on conditionJNI global references: 5可以通過調用 Thread.getAllStackTraces() 方法完成 jstack的大部分功能;
【荔枝】
/*** Thread.getAllStackTraces獲取虛擬機中所有線程的StackTraceElement對象* , 模擬jstack的大部分功能 */ public class Page111 {public static void main(String[] args) {for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(new Random(17).nextInt(10)); } }).start(); // // 啟動線程 }for (int i = 0; i < 3600; i++) {System.out.println("================");try {Thread.sleep(1000);/* Thread.getAllStackTraces獲取虛擬機中所有線程的StackTraceElement對象 */Map<Thread, StackTraceElement[]> stackTracks = Thread.getAllStackTraces();for (Map.Entry<Thread, StackTraceElement[]> entry : stackTracks.entrySet()) {System.out.println("key = " + entry.getKey().getName() + ", value = " + entry.getValue());StackTraceElement[] elements = entry.getValue();int index = 1;for (StackTraceElement e : elements) {System.out.println("value[" + index++ +"] = " + e);}}} catch (InterruptedException e) {e.printStackTrace();}}} } // Thread.getAllStackTraces獲取虛擬機中所有線程的StackTraceElement對象,線程方法堆棧信息 key = Finalizer, value = [Ljava.lang.StackTraceElement;@5c647e05 value[1] = java.lang.Object.wait(Native Method) value[2] = java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144) value[3] = java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165) value[4] = java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216) key = Attach Listener, value = [Ljava.lang.StackTraceElement;@33909752 key = Signal Dispatcher, value = [Ljava.lang.StackTraceElement;@55f96302 key = Reference Handler, value = [Ljava.lang.StackTraceElement;@3d4eac69 value[1] = java.lang.Object.wait(Native Method) value[2] = java.lang.Object.wait(Object.java:502) value[3] = java.lang.ref.Reference.tryHandlePending(Reference.java:191) value[4] = java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) key = main, value = [Ljava.lang.StackTraceElement;@42a57993 value[1] = java.lang.Thread.dumpThreads(Native Method) value[2] = java.lang.Thread.getAllStackTraces(Thread.java:1610) value[3] = chapter4.Page111.main(Page111.java:25)7、HSDIS:JIT生成代碼反匯編
HSDIS是一個sun官方推薦的hotspot虛擬機 JIT編譯代碼的反匯編插件,包含在hotspot虛擬機的源碼之中,但沒有提供編譯后的程序。
作用是讓hotspot的-XX:+PrintAssembly 指令調用它來吧動態生成的本地代碼還原為匯編代碼輸出,同時還生成了大量有價值的注釋;
?
【4.3】JDK的可視化工具
JConsole和VisualVM;JConsole是虛擬機監控工具, 而VisualVM是多合一故障處理工具;
1、JConsole:java監視與管理控制臺;基于JMX的可視化監視,管理工具;
1.1、啟動JConsole;
【JConsole監控荔枝】
/*** JConsole 監控jvm內存 * vm params: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8*/ public class Page114JConsoleTest {private static final int _1MB = 1024 * 1024;public static void main(String[] args) {for (int i = 0; i < 3600; i++) {new Thread(new Runnable() {@Overridepublic void run() {byte[] allocation1 = new byte[1 * _1MB]; byte[] allocation2 = new byte[2 * _1MB];byte[] allocation4 = new byte[4 * _1MB];} }).start(); // // 啟動線程try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace(); }}} }1.2、內存監控
/*** JConsole監視代碼 * jvm params: -Xms100m -Xmx100m -XX:+UseSerialGC* @author tang rong* 2019/05/12 */ public class Page117 {public static void main(String[] args) throws Exception {fillHeap(1000);}public static void fillHeap(int num) throws InterruptedException {List<OOMObject> list = new ArrayList<>(); for (int i=0; i<num; i++) {System.out.println(i);/* 稍作延時,令監視曲線的變化更加明顯 */Thread.sleep(50);list.add(new OOMObject());}System.gc(); }static class OOMObject {byte[] placeholder = new byte[64 * 1024];} }1.3、線程監控
線程長時間停頓的主要原因有: 等待外部資源(數據庫連接,網絡資源,設備資源等),死循環,鎖等待(活鎖和死鎖);
【荔枝-線程等待演示代碼】
/*** 線程等待演示代碼* @author tr* 2019/05/12 */ public class Page119 {public static void createBusyThread() {new Thread(new Runnable() {@Overridepublic void run() {while (true) // 死循環;}}, "testBusyThread").start();}public static void createLockThread(final Object lock) {new Thread(new Runnable() {@Overridepublic void run() {synchronized (lock) {try {lock.wait(); // 線程等待 } catch (InterruptedException e) {e.printStackTrace();}}}}, "testLockThread").start(); }public static void main(String[] args) throws Exception {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));br.readLine();createBusyThread(); // 死循環br.readLine();Object obj = new Object(); createLockThread(obj); // 線程等待} }【荔枝-線程死鎖等待演示代碼】
/*** 線程死鎖等待演示 * @author tr* 2019/05/12 */ public class SynAddRunnable implements Runnable {int a, b; public SynAddRunnable(int a, int b) {this.a = a;this.b = b; }@Override public void run() {synchronized (Integer.valueOf(a)) {synchronized (Integer.valueOf(b)) {System.out.println(a+b);}}}public static void main(String[] args) {for (int i=0; i<100; i++) {System.out.println("i = " + i);new Thread(new SynAddRunnable(1, 2)).start(); // 死鎖, 線程1拿到了a鎖,準備拿b鎖,但線程2拿到了b鎖且沒有釋放;new Thread(new SynAddRunnable(2, 1)).start(); // 死鎖,線程2拿到了b鎖,準備拿a鎖,但線程1拿到了a鎖且沒有釋放;} } }出現死鎖后,查看線程列表中被阻塞的線程;
?
【4.3.2】VisualVM:多合一故障處理工具(jvisualvm.exe)
1、VisualVM可以做到:
顯示jvm進程配置信息,環境信息(jps, jinfo);
監視cpu, gc,堆,方法區以及線程信息(jstat, jstack);
dump以及分析堆轉儲快照(jmap,jhat);
方法級的程序運行性能分析,找出被調用最多,運行時間最長的方法;
離線程序快照:收集程序的運行時配置,線程dump,內存dump等信息建立一個快照,可以將快照發送給開發者;
其他plugin的無限可能性;
【補充】VisualVM的兼容性
如果不給VisualVM安裝插件,就放棄了其最精華的功能;
2、生成、瀏覽堆轉儲快照-dump文件
點擊堆dump;
3、分析程序性能:profiler頁簽中分析;
注意: profiling堆程序運行性能有很大影響,一般不在生產環境做;
4、BTrace動態日志跟蹤
4.1、BTrace的作用是:在不停止目標程序運行的前提下,通過hotspot虛擬機的hotswap技術動態加入原本并不存在的調試代碼(如日志信息);
補充:hotswap技術,即代碼熱替換技術, hotspot虛擬機允許在不停止運行的情況下,更新已經加載的類的代碼;
/*** BTrace 跟蹤演示 * @date 2019/05/13*/ public class BTraceTest {public int add(int a, int b) {return a + b; }public static void main(String[] args) throws IOException {BTraceTest test = new BTraceTest();BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));for (int i = 0; i < 10; i++) { reader.readLine();int a = (int) Math.round(Math.random() * 1000);int b = (int) Math.round(Math.random() * 1000);System.out.println("test.add(a, b) = " + test.add(a, b));}} }trace script
/* BTrace Script Template */ import com.sun.btrace.annotations.*; import static com.sun.btrace.BTraceUtils.*;@BTrace public class TracingScript {/* put your code here */@OnMethod(clazz = "chapter4.BTraceTest",method = "add",location = @Location(Kind.RETURN))public static void func(@Self chapter4.BTraceTest instance,int a,int b,@Return int result){println("調用堆棧:");jstack();println(strcat("方法參數A:",str(a)));println(strcat("方法參數B:",str(b)));println(strcat("方法結果:",str(result))); } }BTrace的用法包括: 打印調用堆棧,參數,返回值只是最基本的應用,還可以進行性能監視,定位連接泄漏和內存泄漏,解決多線程競爭問題等;
?
?
總結
以上是生活随笔為你收集整理的jvm高级特性第4章-虚拟机性能监控与故障处理工具的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 松蛾炖鸡怎么做
- 下一篇: JVM参数设置、分析(转)