一、thread dump     

产品是Java写的,运行于JBOSS平台。操作系统为linux当系统出现问题是很,可以通过thread dump分析就可以找到,但这只是解决问题的第一步,即找到问题的所在。

首先:如何产生thread dump日志?

第一步:找到应用程序所在的进 程号,通过top命令可以找到,不详述。

第二步:执行kill -3 pid获取thread dump日志(pid就是第一步获取到的)。注意:在不同的linux环境下执行输出的日志的地方可能不同。在IBMPowerPC小型机上的linux上执行kill -3 pid会在工作目录下产生类似javacore.20100409.161739.7614.0001.txt的文件。而在我所在的环境中,thread dump信息输出到JBOSS的日志文件中的。

其次:获取线程信息

大多数服务器应用都是多线程, 因此必须查到具体是哪些线程占用的CPU高。通过top –H命令可以查看到应用程序的线程信息及占用CPU的情况。

                                                   

PID所在的列即是对应的线程ID,这是十进制的。

最后:找到耗费CPU高的线程及对应的源代码

取上面耗费CPU最高的第一行的PID 4280,将其转化为十六进制得到0x10b8。然后在thread dump日志中搜索0x10b8,将会搜到如下信息:

"Stack.ClientSelector-1" daemon prio=10 tid=0x000000004baeec00 nid=0x10b8 runnable [0x0000000053169000..0x0000000053169c90]

   java.lang.Thread.State: RUNNABLE

       at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)

       at sun.nio.ch.EPollArrayWrapper.poll(Unknown Source)

       at sun.nio.ch.EPollSelectorImpl.doSelect(Unknown Source)

       at sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)

       - locked <0x00002aaac4105468> (a sun.nio.ch.Util$1)

       - locked <0x00002aaac4131670> (a java.util.Collections$UnmodifiableSet)

       - locked <0x00002aaac3f79c78> (a sun.nio.ch.EPollSelectorImpl)

       at sun.nio.ch.SelectorImpl.select(Unknown Source)

       at com.*****.warlock.protocolstack.impl.layer2.nio.ActiveSelectorImpl.callSelect(ActiveSelectorImpl.java:288)

       at com. *****.warlock.protocolstack.impl.layer2.nio.ActiveSelectorImpl.run(ActiveSelectorImpl.java:163)

上面日志中的nid即是线程号。这样可以清晰的看到耗费CPU的源代码的具体位置,可以精确到行号。

 

结束语:thread dump的作用远不只一点,比如还可以从中发现很多应用程序运行问题,比如死锁等。对于该日志还有一个Eclipse插件的可视化分析工具lockness,我试了一下感觉不错。大家可以参考(3)。


二、Java多线程的监控分析工具(VisualVM)

java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我 们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。(注: 实践本文内容的JDK的版本需要1.6.07以上

    什么是VisualVM

    VisualVM是JDK的一个集成的分析工具,自从JDK 6 Update 7以后已经作为Sun 的JDK的一部分。

    VisualVM可以做的:监控应用程序的性能和内存占用情况、监控应用程序的线程、进行线程转储(Thread Dump)或堆转储(Heap Dump)、跟踪内存泄漏、监控垃圾回收器、执行内存和CPU分析,保存快照以便脱机分析应用程序;同时它还支持在MBeans上进行浏览和操作。尽管 VisualVM自身要在JDK6以上的运行,但是JDK1.4以上版本的程序它都能被它监控。

    在JDK1.6.07以上的版本中:到$JAVA_HOME/bin,点击jvisualvm.exe图标就可以启动VisualVM;当然也可以点击这里获取官方的最新版本,支持:英文,中文,日文。

    VisualVM功能集成较多,我们这里只讨论它对象线程的监控分析

    VisualVM监控线程

    当我们运行VisualVM的时候,可以在应用程序》本地中看到VisualVM和eclipse的运行程序,然后我们启动eclipse中的一个线 程:com.longtask.thread.TestVisualVm,可以看到在菜单中多了一个该线程的显示。点击右边的 线程 菜单,可以看到线程运行的跟踪情况。


    点击 thread dump,可以生成该线程的运行情况的tdump文件,通过thread dump提供的相关信息,我们可以看到线程在什么地方被阻塞了以及线程的其他状态。

    把日志另存为文件,到Thread Dump Analyzer的主页点击图标下载TDA,然后用TDA打开刚才VisualVM保存 的 thread dump文件,查看相关的分析结果。

    我们也可以用VisualVM来监控远程java线程的运行情况。

    远程监控:启动RMI服务

    1:新建一个jstatd.all.policy文件,在里面添加以下内容来保证jstatd服务启动的时候不报异常:

grant codebase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};

    2:netstat -ano | grep -i 1099 查看1099端口是否被占用了,如果被占用,则需要选择其他端口来启动jstatd服务

    3:如果端口被占用,用以下方式启动jstatd服务:

    rmiregistry 2020 & jstatd -J-Djava.security.policy=jstatd.all.policy -p 2020

    更多jstatd的文档请参考sun公司的官方文档 这里

    远程监控Jboos服务

1:修改JDK下面的jmx的配置文件:
    切换至$JAVA_HOME所在目录/jre/lib/management下,
    I:将jmxremote.access、jmxremote.password.template权限调整为读写:

        #cp jmxremote.password.template jmxremote.password
        #chmod 600 jmxremote.password
        #chmod 600 jmxremote.access

    II:vi jmxremote.password去掉
        # monitorRole QED
        # controlRole R&D
        的#号

2:在Jboss的启动文件中添加以下信息:

    JAVA_OPTS="-Dcom.sun.management.jmxremote.port=2899 \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -Djava.rmi.server.hostname=10.212.20.9  其他配置"

3:检查启动情况:
    netstat -a | grep -i 2899 查看端口占有情况
    如果2899端口被其他程序占用,在jboss配置文件中调整端口-Dcom.sun.management.jmxremote.port=****

而后在VisualVM中就添加远程连接,选择jmx方式,就可以监控jboss的运行情况了。

三、java常用工具介绍

jstatd
启动jvm监控服 务。它是一个基于rmi的应用,向远程机器提供本机jvm应用程序的信息。默认端口1099。
实例:jstatd -J-Djava.security.policy=my.policy

my.policy文件需要自己建立,内如如下:
grant codebase "file:$JAVA_HOME/lib/tools.jar" {
 permission java.security.AllPermission;
};
这是安全策略文件,因为jdk对jvm做了jaas的安全检测,所以我们 必须设置一些策略,使得jstatd被允许作网络操作

jps
列出所有的jvm实例
实 例:
jps
列出本机所有的jvm实例

jps 192.168.0.77
列出远程服务器192.168.0.77 机器所有的jvm实例,采用rmi协议,默认连接端口为1099
(前提是远程服务器提供jstatd服务)

输出内容如下:
jones@jones:~/data/ebook/java/j2se/jdk_gc$ jps
6286 Jps
6174  Jstat

jconsole
一个图形化界面,可以观察到java进程的 gc,class,内存等信息。虽然比较直观,但是个人还是比较倾向于使用jstat命令(在最后一部分会对jstat作详细的介绍)。

jinfo(linux下特有)
观 察运行中的java程序的运行环境参数:参数包括Java System属性和JVM命令行参数
实例:jinfo 2083
其中2083 就是java进程id号,可以用jps得到这个id号。
输出内容太多了,不在这里一一列举,大家可以自己尝试这个命令。

jstack(linux下特有)
可 以观察到jvm中当前所有线程的运行情况和线程当前状态
jstack 2083
jmap(linux下特有,也是很常用 的一个命令)
观察运行中的jvm物理内存的占用情况。
参数如下:

-heap
:打印jvm heap的情况
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
-histo:live :同上,但是只答应存活对象的情况
-permstat:打印permanent generation heap情况

命令使用:
jmap -heap 2083
可以观察到New Generation(Eden Space,From Space,To Space),tenured generation,Perm Generation的内存使用情况

jmap -histo 2083 | jmap -histo:live 2083
可以观察heap中所有对象的情况(heap中所有生存的对 象的情况)。包括对象数量和所占空间大小。

写个脚本,可以很快把占用heap最大的对象找出来,对付内存泄漏特别有效。

jstat
最后要重点介绍下这个 命令。
这是jdk命令中比较重要,也是相当实用的一个命令,可以观察到classloader,compiler,gc相关信息
具体参数 如下:
-class:统计class loader行为信息
-compile:统计编译行为信息
-gc:统计jdk gc时heap信息
-gccapacity:统计不同的generations(不知道怎么翻译好,包括新生区,老年区,permanent区) 相应的heap容量情况
-gccause:统计gc的情况,(同-gcutil)和引起gc的事件
-gcnew:统计gc时,新生代的情 况
-gcnewcapacity:统计gc时,新生代heap容量
-gcold:统计gc时,老年区的情况
-gcoldcapacity: 统计gc时,老年区heap容量
-gcpermcapacity:统计gc时,permanent区heap容量
-gcutil:统计 gc时,heap情况
-printcompilation:不知道干什么的,一直没用过。

一般比较常用的几个参数是:
jstat -class 2083 1000 10 (每隔1秒监控一次,一共做10次)
输出内容含义如下:

Loaded Number of classes loaded.
Bytes Number of Kbytes loaded.
Unloaded Number of classes unloaded.
Bytes Number of Kbytes unloaded.
Time Time spent performing class load and unload operations.






 

 

jstat -gc 2083 2000 20(每隔2秒监控一次,共做10)
输出内容含义如下:

S0C Current survivor(存活的) space 0 capacity (KB).
EC Current eden space capacity (KB).
EU Eden space utilization (KB).
OC Current old space capacity (KB).
OU Old space utilization (KB).
PC Current permanent space capacity (KB).
PU Permanent space utilization (KB).
YGC Number of young generation GC Events.
YGCT Young generation garbage collection time.
FGC Number of full GC events.
FGCT Full garbage collection time.
GCT Total garbage collection time.








 

 

 

 

 

 

 

 

 

 

 监控内存使用情况 参数 (查看内存溢出相对有用)

jstat -gccause 2083 5000 (每隔5秒监控一次)
输出内容含义如下:

 

 

S0 Survivor space 0 utilization as a percentage of the space's current capacity.
S1 Survivor space 1 utilization as a percentage of the space's current capacity.
E Eden space utilization as a percentage of the space's current capacity.
O Old space utilization as a percentage of the space's current capacity.
P Permanent space utilization as a percentage of the space's current capacity.
YGC Number of young generation GC events.
YGCT Young generation garbage collection time.
FGC Number of full GC events.
FGCT Full garbage collection time.
GCT Total garbage collection time.
LGCC Cause of last Garbage Collection.
GCC Cause of current Garbage Collection.

 

 

 

 

 

 

 

 

 

GitHub 加速计划 / li / linux-dash
6
1
下载
A beautiful web dashboard for Linux
最近提交(Master分支:3 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐