用于内存泄漏的java堆和线程分析

时间:2016-06-02 13:38:52

标签: java multithreading garbage-collection weblogic12c

我的WebLogic服务器配置了16GB的堆空间,但是当大多数用户开始工作时,在生产使用的1小时内使用了90%。我发现只要发生这种情况,就会发现几个卡住的线程。

当堆大约10%空闲时,我已经捕获了堆转储。如何检查堆转储以查找导致此问题的内存泄漏或进程代码。

我试图了解内存泄漏,运行JMap和Eclipse MAT等工具,但可能由于缺乏经验,我无法理解这些工具试图展示的内容。或者我应该如何/应该注意什么?

我要分析前后GC堆转储。

我已经审查了线程转储,没有"等待锁定"对象线程,线程类似如下所示,线程卡住没有明显的原因。

6 个答案:

答案 0 :(得分:2)

根据您的堆转储,您最大的内存问题是 int arrays ,实际上它需要 70%的堆(是的,而不是对大小列进行排序)。

  1. 在堆转储中选择它,右键单击并选择Show in Instances View
  2. 然后浏览最大的对象,并右键单击并选择Show Nearest GC Root以查看哪个对象仍然是对int数组的硬引用,这会阻止其符合GC的条件。
  3. 它可以帮助您找到内存泄漏,假设它是内存泄漏。

    请参阅下面的Nearest GC Root示例,该示例允许识别我故意添加到程序中的泄漏,以显示该想法。正如您在屏幕截图中看到的,我有一个int数组,它不符合GC的条件,因为它存储在我的班级HashMap中名为leak的{​​{1}}中,所以我知道我的记忆问题可能是由于这个特殊的Application,特别是如果我有许多其他对象导致这个HashMap

    enter image description here

    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服务器,所以:

    1. 启动http://localhost:7000/
    2. 然后点击7000
    3. 然后,您将看到按创建的新实例总数排序的类列表。然后,您可以使用VisualVM执行我在答案的第一部分中描述的内容,以找出内存泄漏的根本原因。

      您也可以使用Show instance counts for all classes (including platform)

      1. 通过为每个人选择顶级课程
      2. 点击一个“参考此对象”
      3. 然后点击jhat
      4. 然后,您将看到每个实例的GC根,如下一个屏幕截图:

        enter image description here

        另一种方法是使用Eclipse Memory Analyzer也称为Exclude weak refs

        1. 用它打开第二个快照
        2. 选择视图MAT
        3. 然后为每个顶级课程右键单击
        4. 选择histogram / Merge Shortest Paths To GC Roots
        5. 然后,您将看到类似下一个屏幕截图的内容:

          enter image description here

答案 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可能对你有所帮助。