如何快速确认由具体某个类引起的JVM内存泄漏

在流量大致稳定的情况下, JVM 运行一段时间之后, 它的内存使用会趋于稳定, 我们通常认为这个时候做完一次 Full GC 之后的使用内存为稳定使用内存, 一般我们对 JVM 堆(heap) 大小的设置通常对比这个值做参考, 设置年轻代, 老年代的值. 当发生内存泄漏的时候, FuLL GC 之后的内存使用量表现为逐渐增大, 直到内存全部耗尽, 频繁的发生 full GC. 对于内存泄漏的问题, 我们一般捕获 heap dump, 然后分析, 当一个或一类对象实例所直接或间接占用的内存比例非常高的时候, 或者占用巨大的时候, 我们就会怀疑该类或对象. 那么有没有在不做 heap dump 的情况下, 快速定位某个对象是不是发生内存泄漏的方法呢?

JDK 自带的 jcmd 和 jmap 都提供了一个打印类的 histo 的方法:

jmap -histo 7769 
 num     #instances         #bytes  class name
----------------------------------------------
   1:       3371196      577233640  [C
   2:        648010      190750288  [I
   3:       5246939      167902048  java.util.HashMap$Entry
   4:        306414      167572840  [B
   5:        406154       58004920  [Ljava.util.HashMap$Entry;
   6:       2329379       55905096  java.lang.String
   7:        533619       48368048  [Ljava.lang.Object;
    ...
9487:             1             16  org.context.annotation.AnnotationBeanNameGenerator
9488:             1             16  org.apache.catalina.connector.Request$2
Total      20285661     1595430008

或者使用 jcmd

jcmd  7769 GC.class_histogram | grep CalTransactionImpl
1160:            17           1088  com.tianxiaohui.CalTransactionImpl

在稳定运行一段时间之后, 间隔一段时间运行这些命令, 就能对比出来某个类的实例是不是一直在增长. 通常情况下某个类的实例多少应该稳定在某个值附近, 若一直增长, 通常说明有某些问题.

jmap 可以使用 -live 选项, jcmd 的 GC.class_histogram 子命令可以使用 -all 选项.

标签: none

添加新评论