在没有进行垃圾回收的情况下,是否可以创建堆转储以分析内存泄漏?

21

我们在生产环境的虚拟机上运行Java应用程序时存在一些内存泄漏问题,老年代堆使用量每天都在快速增长,因此我想创建堆转储以进行分析。

但是,我注意到VisualVM会在堆转储之前执行完整的GC,这将清除老年代,在这种情况下,堆转储将毫无用处。

我还尝试使用以下命令:

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

它也会触发完整的GC。

我想问一下是否有一种方法可以在不进行完整的GC(或不进行GC)的情况下创建堆转储?或者有没有更好的方法来分析内存泄漏?

JDK版本:1.7.0_45

谢谢。

4个回答

34

被标记为正确答案的答案不再正确。

正如Sumit所说,只有在使用live选项(在histo和dump操作中)时,它才会导致Full GC。

Java 7Java 8都有这个选项

-histo[:live]

打印堆的直方图。对于每个Java类,都会打印对象数量、内存大小(以字节为单位)和完全限定类名。JVM内部类名以星号(*)前缀打印。如果指定了live子选项,则仅计算活动对象。


-dump:[live,] format=b, file=filename 将Java堆以hprof二进制格式转储到文件名中。live子选项是可选的,但指定时仅转储堆中活动对象。要浏览堆转储,可以使用jhat(1)命令读取生成的文件。
您还可以使用操作GC.heap_dump和选项-all的jcmd命令。
GC.heap_dump 生成Java堆的HPROF格式转储。
影响:高:取决于Java堆的大小和内容。请求完全GC,除非指定了-all选项。
权限:java.lang.management.ManagementPermission(monitor)
语法:GC.heap_dump [options]
参数: - filename: 转储文件的名称(STRING,没有默认值)
选项:(必须使用或=语法指定选项) - all: [可选] 转储所有对象,包括不可访问对象(BOOLEAN,false)
示例:jcmd 3181 GC.heap_dump -all dump 您可以添加-XX:+PrintGCDetails标志来查看是否正在进行完全GC。例如,当我使用没有-all的jcmd时,我会看到类似以下内容的消息。
200,658: [全垃圾回收(初始化堆转储) 200,658: [CMS: 5040K->4158K(18432K), 0.0171885秒] 11239K->4158K(25856K), [元空间: 18053K->18053K(1064960K)], 0.0173941秒] [时间: 用户=0.01系统=0.00, 实际=0.02秒]

9

8
为了创建堆转储,需要进行Full GC。当从堆中创建Class直方图时也是如此。
如果想要在Full GC之间分析内存泄漏,则可能只能使用Java分析器(Mission Control、jProfiler等)进行内存分析。
请参阅Java Mission Control Heap Profile中的问答。

我尝试使用任务控制并在VM上添加-XX:+ UnlockCommercialFeatures-XX:+ FlightRecorder以启用Flight Recorder,但是我无法启动应用程序。我收到错误消息,提示“初始化JFR时出错。 JFR将被停用。 java.lang.Exception:无法检测Throwable! 在oracle.jrockit.jfr.VMJFR.instrument(VMJFR.java:408) 在oracle.jrockit.jfr.JFR.init(JFR.java:108)” - zhengyu

2

只需将选项中的“live”删除,您就可以了。当您向jmap提供“live”选项时,您强制JVM运行Full GC并捕获那些应该是“活动”的对象。 请改用jmap -dump:format=b,file=hd.hprof。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接