Linux下如何对Java线程进行分析?

在生产环境(Linux)有什么办法知道当前某个线程的运行情况,比如是不是挂住了,是不是吃了好多cpu和内存。 这篇文章中:一次简单却致命的错误 作者 “查看java进程线程栈,我发现线程栈里面的线程都RUNNABLE在32行。”这个是怎么做到的啊? 谢谢
关注者
461
被浏览
59,639

10 个回答

@jiacheo 已经基本上回答清楚了。 对于某个线程的内存占用,是无法知道的(因为是共享内存的)。(查看cpu占用率 top -Hp 这个在 mac os 下没有效果)

对于线程是否挂住的处理一般是这样:
1. 先进行一次thread dump (jstack -m <pid> 或者 kill -3 <pid> , 或者使用jconsole, jvisualvm等) (jstack 命令有一些选项不是每个平台都支持的, jconsole jvisualvm都是有界面的, 如果你要运行一般需要配置agent或者重定向display到某台机器).

2. 然后过了一段时间再做一次, 如果发现同一个thread NID 还是停在同一个地方, 基本上可以怀疑是否挂住了(一般只需要查看你业务相关的stack信息就行了).

3. 还有一种就是你的日志很详细, 也可以看到一些的情况(打印到某个地方就卡住了, 呵呵).

JVM的内存问题:
1. 这个首先建议所有的应用都加上GC log , 他能告诉你每次gc是快还是满,有多频繁, 如果配合其他参数还能输出很多有用的参考信息.

2. 请应用都配置上-XX:+HeapDumpOnOutOfMemoryError , 如果OOM 会有memory dump, 可以使用MAT进行分析, 可以知道很多你想要的知道的请情况.

3. 另外就是可以手工进行一些memory dump(jmap -dump:file=xxx.bin <pid> 如果是1.5, jmap -heap:format=b <pid>), 不过对于堆比较大的java应用,会暂停很长时间。对线上系统使用请谨慎.

4. 上面都是对一些堆的情况分析。 如果是堆外的,某一些情况是可以通过JVM的特定参数可以拿到(可以使用jinfo 命令拿到很多东西, 还可以使用btrace 等), 其他的就是就是和分析c/c++程序一样了。

性能:
1. 如果是查看性能可以使用oprofile, 或者淘宝的tprofiler, 各种profiler等, 可以查看到某个api的运行时间(profiler 对应用性能一定有一些影响, 所以如果是对线上的系统使用profiler请谨慎).

2. 如果是线上系统(之前没有配置过什么profiler的东西, 又不想停机), 可以简单的使用btrace 进行某个api的拦截, 打印出每次运行的时间(前提是你已经怀疑了某个方法).

以下是针对tomcat上的应用的. 其他的java程序, 只要你能触发他的thread dump并且拿到结果, 也是一样.
1. ps -ef | grep java
找到你的java程序的进程id, 定位 pid
2. top -Hp $pid
shift+t
查看耗cpu时间最多的几个线程, 记录下线程的id
3. 把上诉线程ID转换成16进制小写 比如 : 0x12ef
4. kill -3 $pid 触发tomcat的thread dump
5. 找到tomcat的catalin.out 日志, 把 上面几个线程对应的代码段拿出来.
DONE.
jiacheo.org/blog/279