我的WebLogic服务器配置了16GB的堆空间,但是当大多数用户开始工作时,在生产使用的1小时内使用了90%。我发现只要发生这种情况,就会发现几个卡住的线程。
当堆大约10%空闲时,我已经捕获了堆转储。如何检查堆转储以查找导致此问题的内存泄漏或进程代码。
我试图了解内存泄漏,运行JMap和Eclipse MAT等工具,但可能由于缺乏经验,我无法理解这些工具试图展示的内容。或者我应该如何/应该注意什么?
我要分析前后GC堆转储。
我已经审查了线程转储,没有"等待锁定"对象线程,线程类似如下所示,线程卡住没有明显的原因。
答案 0 :(得分:2)
根据您的堆转储,您最大的内存问题是 int arrays ,实际上它需要 70%的堆(是的,而不是对大小列进行排序)。
Show in Instances View
Show Nearest GC Root
以查看哪个对象仍然是对int数组的硬引用,这会阻止其符合GC的条件。 它可以帮助您找到内存泄漏,假设它是内存泄漏。
请参阅下面的Nearest GC Root
示例,该示例允许识别我故意添加到程序中的泄漏,以显示该想法。正如您在屏幕截图中看到的,我有一个int数组,它不符合GC的条件,因为它存储在我的班级HashMap
中名为leak
的{{1}}中,所以我知道我的记忆问题可能是由于这个特殊的Application
,特别是如果我有许多其他对象导致这个HashMap
。
NB:当您尝试识别泄漏时请耐心等待,因为它并不总是很明显,理想的情况是您拥有占据整个堆的巨大物体,但显然不是您的情况没有什么是明显的,这就是我建议首先研究int数组的原因。不要忘记它也可能是小的int数组,但数千个具有相同的HashMap
。
另一个技巧,如果您有JProfiler,只需按this wonderful tutorial查找泄漏即可。
响应更新:
更好地识别内存泄漏根本原因的一种简单方法是至少进行2次堆转储,然后使用jhat之类的工具与语法进行比较
Nearest GC Root
它将在端口jhat -J-Xmx2G -baseline ${path-to-the-first-heap-dump} ${path-to-the-second-heap-dump}
上启动一个小型HTTP服务器,所以:
7000
然后,您将看到按创建的新实例总数排序的类列表。然后,您可以使用VisualVM执行我在答案的第一部分中描述的内容,以找出内存泄漏的根本原因。
您也可以使用Show instance counts for all classes (including platform)
jhat
然后,您将看到每个实例的GC根,如下一个屏幕截图:
另一种方法是使用Eclipse Memory Analyzer
也称为Exclude weak refs
。
答案 1 :(得分:2)
JDK的“jmap -histo”命令会将所有类的对象计数/字节转储到文本文件中。如果随着时间的推移捕获/比较其中的一些转储,您将看到哪些转储不断增长 - 您的内存泄漏。 -histo的开销远低于捕获完整堆转储的开销。
只比较几个转储(比如python脚本detailed here)似乎太小了,所以我编写了一个开源工具(here)来运行这个jmap -histo命令背景(间隔)。它具有实时显示并跟踪每个类的字节数正在增加的时间百分比。
答案 2 :(得分:1)
看起来你可能有内存泄漏的情况。您最好的方法是使用Java Mission Control和Flight Recorder来获取类和方法泄漏。
您应该使用以下参数设置您的weblogic托管服务器:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
设置时,请按照here说明检测泄漏。
希望它有所帮助!!
答案 3 :(得分:1)
我是名为Plumbr的工具的开发人员之一。除此之外,我们在内存使用过多的情况下自动分析堆内容。您可能会发现它很有用。
答案 4 :(得分:1)
根据您的意见:您拥有16 GB堆的Java 7,没有明确指定GC算法,因此Java 7的默认值是吞吐量GC,它不适用于大多数Web应用程序,因为它会导致很长时间的GC暂停。
切换到ConcurrentMarkSweep GC,这样GC就不会等到你的内存填满并且会尽力逐步收集垃圾,这样你就可以减少Stop The World暂停。
答案 5 :(得分:1)
你试过yourkit profiler吗?它不是免费的,但你可以评估它30天。在这种情况下,如果转储包含所有对象(不仅是实时),您也可以检查它们的根。因为你可能没有内存泄漏,但是memory footprint太大了。对enable GC logs也很好,并解析你有多少FullGC停顿:
grep "Full GC" jvm_gc.log | wc -l
在理想世界中它应该是0:)
顺便说一下,整个article可能对你有所帮助。