Java线程Dump分析工具jstack解析及使用场景
jstack用于打印出给定的java进程ID或corefile或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式:
jstack[-l][F]pid
如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的javastack和nativestack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的javastack和nativestack的信息,如果现在运行的java程序呈现hung的状态,jstack是非常有用的。进程处于hung死状态可以用-F强制打出stack。
dump文件里,值得关注的线程状态有:
死锁,Deadlock(重点关注)
执行中,Runnable
等待资源,Waitingoncondition(重点关注)
等待获取监视器,Waitingonmonitorentry(重点关注)
暂停,Suspended
对象等待中,Object.wait()或TIMED_WAITING
阻塞,Blocked(重点关注)
停止,Parked
在摘了另一篇博客的三种场景:
实例一:Waitingtolock和Blocked
"RMITCPConnection(267865)-172.16.5.25"daemonprio=10tid=0x00007fd508371000nid=0x55aewaitingformonitorentry[0x00007fd4f8684000] java.lang.Thread.State:BLOCKED(onobjectmonitor) atorg.apache.log4j.Category.callAppenders(Category.java:201) -waitingtolock<0x00000000acf4d0c0>(aorg.apache.log4j.Logger) atorg.apache.log4j.Category.forcedLog(Category.java:388) atorg.apache.log4j.Category.log(Category.java:853) atorg.apache.commons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234) atcom.tuan.core.common.lang.cache.remote.SpyMemcachedClient.get(SpyMemcachedClient.java:110)
说明:
1)线程状态是Blocked,阻塞状态。说明线程等待资源超时!
2)“waitingtolock<0x00000000acf4d0c0>”指,线程在等待给这个0x00000000acf4d0c0地址上锁(英文可描述为:tryingtoobtain0x00000000acf4d0c0lock)。
3)在dump日志里查找字符串0x00000000acf4d0c0,发现有大量线程都在等待给这个地址上锁。如果能在日志里找到谁获得了这个锁(如locked<0x00000000acf4d0c0>),就可以顺藤摸瓜了。
4)“waitingformonitorentry”说明此线程通过synchronized(obj){……}申请进入了临界区,从而进入了下图1中的“EntrySet”队列,但该obj对应的monitor被其他线程拥有,所以本线程在EntrySet队列中等待。
5)第一行里,"RMITCPConnection(267865)-172.16.5.25"是ThreadName。tid指JavaThreadid。nid指native线程的id。prio是线程优先级。[0x00007fd4f8684000]是线程栈起始地址。
实例二:Waitingoncondition和TIMED_WAITING
"RMITCPConnection(idle)"daemonprio=10tid=0x00007fd50834e800nid=0x56b2waitingoncondition[0x00007fd4f1a59000] java.lang.Thread.State:TIMED_WAITING(parking) atsun.misc.Unsafe.park(NativeMethod) -parkingtowaitfor<0x00000000acd84de8>(ajava.util.concurrent.SynchronousQueue$TransferStack) atjava.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198) atjava.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424) atjava.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323) atjava.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874) atjava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) atjava.lang.Thread.run(Thread.java:662)
说明:
1)“TIMED_WAITING(parking)”中的timed_waiting指等待状态,但这里指定了时间,到达指定的时间后自动退出等待状态;parking指线程处于挂起中。
2)“waitingoncondition”需要与堆栈中的“parkingtowaitfor<0x00000000acd84de8>(ajava.util.concurrent.SynchronousQueue$TransferStack)”结合来看。首先,本线程肯定是在等待某个条件的发生,来把自己唤醒。其次,SynchronousQueue并不是一个队列,只是线程之间移交信息的机制,当我们把一个元素放入到SynchronousQueue中时必须有另一个线程正在等待接受移交的任务,因此这就是本线程在等待的条件。
3)别的就看不出来了。
实例三:inObejct.wait()和TIMED_WAITING
"RMIRenewClean-[172.16.5.19:28475]"daemonprio=10tid=0x0000000041428800nid=0xb09inObject.wait()[0x00007f34f4bd0000] java.lang.Thread.State:TIMED_WAITING(onobjectmonitor) atjava.lang.Object.wait(NativeMethod) -waitingon<0x00000000aa672478>(ajava.lang.ref.ReferenceQueue$Lock) atjava.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) -locked<0x00000000aa672478>(ajava.lang.ref.ReferenceQueue$Lock) atsun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run(DGCClient.java:516) atjava.lang.Thread.run(Thread.java:662)
说明:
1)“TIMED_WAITING(onobjectmonitor)”,对于本例而言,是因为本线程调用了java.lang.Object.wait(longtimeout)而进入等待状态。
2)“WaitSet”中等待的线程状态就是“inObject.wait()”。当线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(一般就是被synchronized的对象)的wait()方法,放弃了Monitor,进入“WaitSet”队列。只有当别的线程在该对象上调用了notify()或者notifyAll(),“WaitSet”队列中线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。
3)RMIRenewClean是DGCClient的一部分。DGC指的是DistributedGC,即分布式垃圾回收。
4)请注意,是先locked<0x00000000aa672478>,后waitingon<0x00000000aa672478>,之所以先锁再等同一个对象,请看下面它的代码实现:
staticprivateclassLock{}; privateLocklock=newLock(); publicReferenceremove(longtimeout) { synchronized(lock){ Referencer=reallyPoll(); if(r!=null)returnr; for(;;){ lock.wait(timeout); r=reallyPoll(); …… } }
即,线程的执行中,先用synchronized获得了这个对象的Monitor(对应于locked<0x00000000aa672478>);当执行到lock.wait(timeout);,线程就放弃了Monitor的所有权,进入“WaitSet”队列(对应于waitingon<0x00000000aa672478>)。
5)从堆栈信息看,是正在清理remotereferencestoremoteobjects,引用的租约到了,分布式垃圾回收在逐一清理呢。
referance:
通过jstack分析解决进程死锁问题实例代码
总结
以上就是本文关于Java线程Dump分析工具jstack解析及使用场景的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!