检查java内存泄露_Java应用内存泄露排查

JVM如果出现内存泄露,典型的现象就是系统FullGC比较频繁。到最后干脆OOM(Out of Memory)了。

当发现应用内存溢出或长时间使用内存很高的情况下,通过内存dump进行分析可找到原因。

当发现cpu使用率很高时,通过线程dump定位具体哪个线程在做哪个工作占用了过多的资源。

内存dump是指通过jmap -dump 输出的文件,而线程dump是指通过jstack 输出的信息。

在linux操作系统下(已安装jdk),执行jps命令,列出正在运行的java程序的进程ID。

bacd66138e9a

jps

使用top查看目前正在运行的进程使用系统资源情况。

bacd66138e9a

top

首先是内存dump:

jmap –dump:live,format=b,file=heap.bin

可以用jmap -h查看详细信息:

where is one of:

to print same info as Solaris pmap

-heap to print java heap summary

-histo[:live] to print histogram of java object heap; if the "live"

suboption is specified, only count live objects

-permstat to print permanent generation statistics

-finalizerinfo to print information on objects awaiting finalization

-dump: to dump java heap in hprof binary format

dump-options:

live dump only live objects; if not specified,

all objects in the heap are dumped.

format=b binary format

file= dump heap to

Example: jmap -dump:live,format=b,file=heap.bin

-F force. Use with -dump: or -histo

to force a heap dump or histogram when does not

respond. The "live" suboption is not supported

in this mode.

-h | -help to print this help message

-J to pass directly to the runtime system

其次是线程dump,比如说:

jstack -m >jvm_deadlocks.txt

jstack -l >jvm_listlocks.txt

可以用 jstack -h 查看命令详细信息

Options:

-F to force a thread dump. Use when jstack does not respond (process is hung)

-m to print both java and native frames (mixed mode)

-l long listing. Prints additional information about locks

-h or -help to print this help message

但是dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程太折腾不到万不得已最好别这么干。

可以用更轻量级的在线分析,用jmap查看存活的对象情况(jmap -histo:live [pid])。

bacd66138e9a

jmap

比如上图所示,HashTable占用了大量的内存,如何找到导致这个事情发生的原因?可以进一步使用btrace来排查。

首先写btrace脚本TracingHashTable.java:

import com.sun.btrace.annotations.*;

import static com.sun.btrace.BTraceUtils.*;

@BTrace

public class TracingHashTable {

@OnMethod(

clazz="java.util.Hashtable",

method="put",

location=@Location(Kind.RETURN))

public static void traceExecute(@Self java.util.Hashtable object){

println("调用堆栈!!");

jstack();

}

然后运行:

bin/btrace -cp build 4947 TracingHashTable.java

可以看到下面的堆栈:

bacd66138e9a

堆栈

至此就定位到具体出问题的代码行了。

但是说实话,内存泄露这种问题,好好写代码用好static变量和容器,是很容易避免的。

那么考虑一种特殊的很难发现和避免的情况,永久代内存泄露。

bacd66138e9a

内存详细信息

上图说明Perm不足. Perm存放class,method相关对象,以及运行时常量对象. 如果一个应用加载了大量的class, 那么Perm区存储的信息一般会比较大.另外大量的intern String对象也会导致Perm区不断增长。 此区域大小由-XX:MaxPermSize参数进行设置。

一般出现这种问题的原因,目前只发现两种:Groovy动态编译class、String.intern。

本质原因,是ClassLoader.defineClass和java.lang.String.intern在大量不适宜的场景被调用。

使用btrace相关工具输出调用ClassLoader.defineClass栈信息, 从栈信息来追溯问题. (代码如下图). 但Btrace 不能trace native方法。

bacd66138e9a

batrace

此外,可以用Jprofiler来trace String.intern方法栈,这块就需要单独去研究了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值