我有一个Java应用程序,我从控制台运行,然后控制台执行另一个Java进程.我想获得该子进程的线程/堆转储.
在Unix上,我可以做一个kill -3 <pid>
但是在Windows AFAIK上获取线程转储的唯一方法是在控制台中使用Ctrl-Break.但这只会让我转移父进程,而不是孩子.
有没有另一种方法来获得堆转储?
我试图更多地了解java,尤其是关于内存管理和线程.出于这个原因,我最近发现有兴趣查看线程转储.
以下是使用VisualVM(一种用于java的内置工具)从Web应用程序中获取的几行:
"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
Locked ownable synchronizers:
- None
"Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x27ef0310> (a java.lang.ref.Reference$Lock)
Run Code Online (Sandbox Code Playgroud)
首先,我对一些变量名称有疑问:
然后为堆栈跟踪本身:
当Java应用程序挂起时,您甚至不知道导致这种情况的用例并想要调查,我理解线程转储可能很有用.
但是,我们如何从线程转储中轻松地获取有用的数据以找出问题所在?我一直在使用的服务器应用程序产生很长的线程转储,因为它是一个EJB体系结构,并且线程转储包含许多容器线程,我不确定我应该关注它们(即没有运行我的应用程序代码的线程) ,但JBoss的代码).
昨天我尝试了Thread Dump Analyzer工具.该工具肯定比在文本编辑器中查看原始线程转储更好,因为您可以过滤掉您不感兴趣的线程,查看线程列表,单击线程以查看其详细信息,比较线程转储以查找长时间运行的线程等.见下面的截图:
但仍有太多数据需要分析 - 近300个线程.我不知道有什么标准可以用来过滤掉所有我不感兴趣的JBoss线程.我不确定我是否应该查看当前处于"可运行"状态的线程,或者"等待条件"和"在Object.wait"中的线程也很重要.
您通常会遵循的方法和一般使用的工具是什么?
我正在运行Ubuntu服务器版,我想采取Tomcat的线程转储.
所以,我首先尝试找出哪个PID tomcat使用:
$ jps -l
5809 sun.tools.jps.Jps
Run Code Online (Sandbox Code Playgroud)
但它不在那里?
所以,我用了之后top
发现了PID 5730.
然后我调用jstack来获取线程转储:
$ sudo jstack -l 5730
5730: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?:-(
我已经尝试按照Jstack中的描述导出CATALINA_TMPDIR,并且Jstat停止使用升级到JDK6u23但是没有改变任何东西:
$ export CATALINA_TMPDIR=/tmp
$ sudo /etc/init.d/tomcat6 restart
* Stopping Tomcat servlet engine tomcat6
...done.
* Starting Tomcat servlet engine tomcat6
...done.
$ sudo jstack -l 5934 // …
Run Code Online (Sandbox Code Playgroud) 在Java线程转储中,您可以看到堆栈跟踪中提到的锁.
似乎有三种信息:
1:
- locked <0x00002aab329f7fa0> (a java.io.BufferedInputStream)
Run Code Online (Sandbox Code Playgroud)
2:
- waiting to lock <0x00002aaaf4ff6fa0> (a org.alfresco.repo.lock.LockServiceImpl)
Run Code Online (Sandbox Code Playgroud)
3:
- parking to wait for <0x00002aaafbf70bb8> (a java.util.concurrent.SynchronousQueue$TransferStack)
Run Code Online (Sandbox Code Playgroud)
我的应用程序Gson 2.2
用于转换POJOs
为JSON
.当我进行负载测试时,我偶然发现Gson
构造函数中阻塞了很多线程:
"http-apr-28201-exec-28" #370 daemon prio=5 os_prio=0 tid=0x0000000001ee7800 nid=0x62cb waiting for monitor entry [0x00007fe64df9a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.google.gson.Gson.<init>(Gson.java:200)
at com.google.gson.Gson.<init>(Gson.java:179)
Run Code Online (Sandbox Code Playgroud)
线程转储不显示任何线程持有[0x00007fe64df9a000] monitor
.
我怎样才能知道谁拥有它?
Gson
第200行的代码看起来很无辜:
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
Run Code Online (Sandbox Code Playgroud)
我使用JRE 1.8.0_91
上Linux
我正在继续深入理解Java Thread.不幸的是,我的Java认证没有涵盖那部分,因此唯一的学习方法是发布一系列愚蠢的问题.经过这么多年的Java开发,我有时想知道我还有多少要学习:-)
特别是我现在关注的是引用处理程序线程.
"Reference Handler" daemon prio=10 tid=0x02da3400 nid=0xb98 in Object.wait() [0x0302f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x1aac0320> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
- locked <0x1aac0320> (a java.lang.ref.Reference$Lock)
Run Code Online (Sandbox Code Playgroud)
现在有一些问题,其中一些我知道答案,但我不发布,因为我想听听别人的意见:
像往常一样,我请求回答所有问题,以便我能够回答.
我正在分析获取线程转储的方法之间的差异.以下是我正在研究的几个人
定义一个jmx bean,它在单击声明的bean操作时通过Runtime.exec()触发jstack.
守护程序线程在预定义的时间间隔后重复执行"ManagementFactory.getThreadMXBean().dumpAllThreads(true,true)".
比较两者之间的线程转储输出,我在方法2中看到了以下缺点
我很感激获得建议/意见
在生产代码中通过Runtime.exec()执行jstack是否有任何缺点?各种操作系统上的兼容性问题 - windows,linux?
采取线程转储的任何其他方法?
谢谢.
编辑 -
1和2的组合方法似乎是要走的路.我们可以在后台运行专用线程,并以线程转储分析器可以理解的格式在日志文件中打印线程转储.如果需要任何额外的信息(比如说可能是本机线程id)只能由jstack输出记录,我们会根据需要手动执行.
我试图了解Locked ownable synchronizers
线程转储中引用的内容?
我开始使用ReentrantReadWriteLock
一个处于WAITING
状态的线程,等待状态(a )ReentrantReadWriteLock$FairSync
中另一个线程的"锁定的可拥有同步器"列表中的WAITING
a ThreadPoolExecutor
.
我找不到太多关于此的信息.这是某种锁"传递到"线程吗?我试图弄清楚我的死锁来自哪里,我看不到任何线程主动锁定那些(即- locked <0x...>
在任何堆栈跟踪中没有对应).
有没有从Tomcat 采取线程转储.我想在特定时间监视Tomcat上正在运行的线程.
注意:我在Web逻辑上这样做,但我不知道如何在Tomcat上完成它.