我有一个Java应用程序,似乎正在泄漏内存,但是我无法找到确定根本原因的方法。而且,我从MemoryMXBean 获得的堆内存使用情况与我从从堆转储获得的结果很不相同。
根据:
((double) memoryMXBean.getHeapMemoryUsage().getUsed()) / (1024 * 1024)
随着时间的推移,堆内存的使用从最初的55MB增加到运行4天后的90MB。
但是开始运行4天后收集的堆转储为28.7MB和34MB。
MemoryMXBean heap_dump
beginning 55MB 28.7MB
after 4 days 90MB 34MB
该应用程序基于作业。这意味着它在大多数时间都保持空闲状态,直到每天的工作开始产生工作量。可以看出,堆内存使用量开始于55MB左右,每天每天攀升一次,直到重新启动应用程序为止。在没有部署几天后的高峰期,堆使用量可能高达110MB。
以下是启动应用程序的方式:
jdk1.8/bin/java
-Dpid=29816
-Dscript=someApp
-Djdbc.drivers=someDriver
-Xmx256M
-Duser.timezone=UTC
-Djavax.net.ssl.trustStore=someTrustStore.jks
-Djavax.net.ssl.trustStorePassword=*****
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintTenuringDistribution
-XX:+PrintGCCause
-XX:+PrintGCApplicationStoppedTime
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/output/logs
-Xloggc:/tmp/output/logs/someApp-gclog
package.SomeApp
我通过以下命令从服务器获得了堆转储:
jmap -dump:format=b,file=<FILENAME> <PID>
我的问题是:
启动后,应用程序的堆转储在堆转储中具有以下信息:
Used heap dump 28.7 MB
Number of objects 594,867
Number of classes 8,929
Number of class loaders 84
Number of GC roots 2,710
Format hprof
JVM version
Time 2:30:45 PM PDT
Date Apr 8, 2019
Identifier size 64-bit
Compressed object pointers true
File path /tmp/20190408_lessThanOneDay_6168.hprof
File length 71,387,808
已运行4天的堆的转储为:
Used heap dump 34 MB
Number of objects 677,239
Number of classes 9,162
Number of class loaders 92
Number of GC roots 2,859
Format hprof
JVM version
Time 9:00:15 AM PDT
Date Apr 8, 2019
Identifier size 64-bit
Compressed object pointers true
File path /tmp/20190408_4days_19324.hprof
File length 120,467,694
答案 0 :(得分:0)
堆转储格式不包含完整信息,例如有关内存填充的信息,并强制显示工具进行猜测。请参阅What Heap Dumps Are Lying To You About文章,其中深入探讨了问题详细信息,表明工具将显示不同的估算值。总计为:
- 大多数基于HPROF的工具在推断实际实例占用空间方面存在问题;本文的特制示例显示实际实例大小与估计实例大小之间的差异> 25%,这可能导致分析方向错误。但是,这种情况很少见,大多数分析都应该很好,特别是在处理千兆字节的内存泄漏时。
- 有人在讨论要修复HPROF,但最终结果是“我们只需要更好的格式”,因为工具已经对HPROF的实际含义有所保留。 JEP,有人吗?
- 在线工具是找出实际实例占用空间的最佳工具。使用JOL,通过命令行运行它,并将其嵌入到您的项目中。您永远都不会,通过查看堆转储来猜测对象的布局。