分析Java 死锁以及MemoryLeak问题

 
    最近一直在解决memorylink问题,觉得有必要记录下这个过程中用到的知识,以免以后忘记。

JDK自身提供了很多关于分析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次)
输出内容含义如下:

LoadedNumber of classes loaded.
BytesNumber of Kbytes loaded.
UnloadedNumber of classes unloaded.
BytesNumber of Kbytes unloaded.
TimeTime spent performing class load and unload operations.






 

jstat -gc 2083 2000 20(每隔2秒监控一次,共做10)

输出内容含义如下:

S0CCurrent survivor(存活的) space 0 capacity (KB).
ECCurrent eden space capacity (KB).
EUEden space utilization (KB).
OCCurrent old space capacity (KB).
OUOld space utilization (KB).
PCCurrent permanent space capacity (KB).
PUPermanent space utilization (KB).
YGCNumber of young generation GC Events.
YGCTYoung generation garbage collection time.
FGCNumber of full GC events.
FGCTFull garbage collection time.
GCTTotal garbage collection time.








 

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

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

S0Survivor space 0 utilization as a percentage of the space's current capacity.
S1Survivor space 1 utilization as a percentage of the space's current capacity.
EEden space utilization as a percentage of the space's current capacity.
OOld space utilization as a percentage of the space's current capacity.
PPermanent space utilization as a percentage of the space's current capacity.
YGCNumber of young generation GC events.
YGCTYoung generation garbage collection time.
FGCNumber of full GC events.
FGCTFull garbage collection time.
GCTTotal garbage collection time.
LGCCCause of last Garbage Collection.
GCCCause of current Garbage Collection.

 









                                                                                                                                                            


除了jconsole, oracle接管java后,提供了一个更强大的工具:jvisualvm

类似于jconsole,但是提供的信息更多,而且可以实时查看dump。强烈推荐。

但是这里有一个权限问题,当在linux上面用jvisualvm时,如果JVM运行的用户跟当前jvisualvm用的用户不是同一个,可能不能sample memory和导dump,所以一定要确保jvisualvm和监视的jvm用的是相同的JVM和相同的用户启动。最好都是root。

如果发现不能连接,尝试修改jboss/jvm参数:

JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Djboss.platform.mbeanserver"
JAVA_OPTS="$JAVA_OPTS -Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl"
JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
JAVA_OPTS="$JAVA_OPTS -Dorg.jboss.logging.Logger.pluginClass=org.jboss.logging.logmanager.LoggerPluginImpl"

然后把loggmanager跟mbean的包加入到classpath中

JBOSS_CLASSPATH="$JBOSS_CLASSPATH:$JBOSS_HOME/lib/jboss-logmanager.jar:$JBOSS_HOME%/lib/jboss-mbeanserver.jar"

                                                                                                                                                            

jvisualVM可以实时的监视和导dump,但有时还需要手动,那么用命令:

jmap -F -dump:live,format=b,file=/var/tmp/java_<pid>_<time>.bin <pid>

导出dump文件后,可以用eclipse memory analyzer来分析它。

-- Peak 结果可以直接帮你看到哪一块是有问题的;

-- Histogram 可以直观的看到内存中各个Obeject的数目和实际retained heap.

-- DominatorTree可以看到各个对象的引用关系,在其中任何一个条目上可以右键去选ListObject或ShowObject by outgoing reference(内部引用外面)或 by incoming reference (外部引用该对象)


里面有两个概念:

 Shallow -- 表示该对象里面指针及引用所占大小

Retained Heap -- 表示该对象里实际占用虚拟内存大小

如果看到shallow 是1,而实际内存又很大,可以点进去分析,多半会发现都是null在占空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值