天天看點

淺析Java堆棧跟蹤工具:Jstack【下】

        上篇講了jstack指令的使用,不知你是否和小編有一樣的想法:我們能否自己寫代碼來實時監控線程堆棧資訊呢?本篇我們将講一下如何在我們的程式中模拟jstack擷取線程堆棧資訊。

       一、 jar包準備

        在我們安裝完jdk後,裡面就有我們的工具包,也許你從沒使用過,今天就到了發揮他們用處的時候了!!!

淺析Java堆棧跟蹤工具:Jstack【下】

jstack有兩種實作方式,一種是基于attach api,其實作可以在tools.jar裡找到;另一種是基于SA的實作,它被放在了sa-jdi.jar裡。如果你通過idea搜尋Jstack類,你會看到tools.jar和sa-jdi.jar各有一個Jstack類。

        二、代碼實戰

上篇我們了解到要檢視線程堆棧資訊,首先要拿到虛拟機執行個體的PID,下面就是拿到PID的代碼。

/**
  * @title: jvmPid
  * @description: 擷取目前虛拟機執行個體運作PID
  * @return int 虛拟機執行個體運作PID
  */
public static final int jvmPid() {
	try {
		RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
		Field jvm = runtime.getClass().getDeclaredField("jvm");
		jvm.setAccessible(true);
		VMManagement mgmt = (VMManagement) jvm.get(runtime);
		Method pidMethod = mgmt.getClass().getDeclaredMethod("getProcessId");
		pidMethod.setAccessible(true);
		int pid = (Integer) pidMethod.invoke(mgmt);
		return pid;
	} catch (Exception e) {
		return -1;
	}
}
           

拿到PID後我們就要開始擷取到線程堆棧資訊了,下面是擷取堆棧資訊的代碼。

/**
 * 
 * @title: getThreadDumpInfo
 * @description: 日志輸出線程堆棧資訊
 * @param pid
 * @throws AttachNotSupportedException
 * @throws IOException
 */
public static final void getThreadDumpInfo(int pid) throws AttachNotSupportedException, IOException {
	VirtualMachine virtualMachine = VirtualMachine.attach(String.valueOf(pid));
	HotSpotVirtualMachine hotSpotVirtualMachine = (HotSpotVirtualMachine) virtualMachine;
	InputStream inputStream = hotSpotVirtualMachine.remoteDataDump(new String[] {});

	byte[] buff = new byte[256];
	int len;
	StringBuffer stringBuffer = new StringBuffer();
	do {
		len = inputStream.read(buff);
		if (len > 0) {
			String respone = new String(buff, 0, len, "UTF-8");
			stringBuffer.append(respone);
		}
	} while (len > 0);
	logger.debug(stringBuffer.toString());
	inputStream.close();
	virtualMachine.detach();
}
           

以下為示例日志。

2019-08-02 16:47:58  [main] [ com.sunshine.vm.DeadLock ] [ 136 ] [ DEBUG ] VM-PID:[ 14744 ]
2019-08-02 16:47:58  [main] [ com.sunshine.vm.DeadLock ] [ 90 ] [ DEBUG ] 2019-08-02 16:47:58
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):

"Thread-2" #12 prio=5 os_prio=0 tid=0x0000000014a4f000 nid=0x2424 waiting on condition [0x00000000154df000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.sunshine.vm.DeadLock.run(DeadLock.java:114)
	- locked <0x00000000ffd39940> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)

"Thread-1" #11 prio=5 os_prio=0 tid=0x000000001499f000 nid=0x5ec waiting on condition [0x00000000153df000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.sunshine.vm.DeadLock.run(DeadLock.java:101)
	- locked <0x00000000ffd39950> (a java.lang.Object)
	at java.lang.Thread.run(Thread.java:748)

"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x00000000141f7800 nid=0x39d8 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000141f3800 nid=0x1f9c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001320f000 nid=0x1628 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001320e800 nid=0x183c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000131b7000 nid=0x1c4c runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000013198800 nid=0x2004 in Object.wait() [0x0000000013edf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00000000ffc08668> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
	- locked <0x00000000ffc08668> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000030ed000 nid=0x39a4 in Object.wait() [0x0000000013ddf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x00000000ffc00b88> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:502)
	at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
	- locked <0x00000000ffc00b88> (a java.lang.ref.Reference$Lock)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x0000000002ffe000 nid=0x2204 runnable [0x0000000002f4e000]
   java.lang.Thread.State: RUNNABLE
	at sun.tools.attach.WindowsVirtualMachine.enqueue(Native Method)
	at sun.tools.attach.WindowsVirtualMachine.execute(WindowsVirtualMachine.java:96)
	at sun.tools.attach.HotSpotVirtualMachine.executeCommand(HotSpotVirtualMachine.java:261)
	at sun.tools.attach.HotSpotVirtualMachine.remoteDataDump(HotSpotVirtualMachine.java:218)
	at com.sunshine.vm.DeadLock.getThreadDumpInfo(DeadLock.java:78)
	at com.sunshine.vm.DeadLock.main(DeadLock.java:137)

"VM Thread" os_prio=2 tid=0x0000000013176800 nid=0x3844 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000003016800 nid=0x39e0 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000003018800 nid=0x2868 runnable 

"VM Periodic Task Thread" os_prio=2 tid=0x000000001420d000 nid=0xeb8 waiting on condition 

JNI global references: 31
           

這樣我們就可以在我們自己的項目中來實時監控我們自己的線程堆棧資訊了。文章到這裡就結束了,如有錯誤,歡迎交流指正,小編繼續查bug去了~