java 堆内存分析_Java 堆内存溢出梗概分析

堆分析

下面我们将详细分析如何使用一个堆分析工具来分析堆转储。在示例中,将使用到 Eclipse 基金会的开源工具 MAT 。

使用 MAT 进行堆分析

是时候进行深入探讨了。我们将通过一系列的步骤,帮助探索在 MAT 中的不同表现和视图,以获取一个堆内存溢出的示例并思考分析。

1. 打开内存溢出错误发生时产生的 .hprof 堆文件。确保复制转储文件到一个专门的文件夹下,因为 MAT 会创建许多索引文件:文件 -> 打开

2. 打开转储文件,有内存泄漏嫌疑报告和组件报告的选项。选择运行泄漏嫌疑报告。

06a0a2e38798376821d4be76db9f0bc0.png

3. 泄漏嫌疑表打开后,在预览窗口的饼状图会展示在每个对象基础上保留内存的分布情况。它显示了内存中的最大对象(拥有最高保留内存的对象 —— 累积的内存和引用的对象)。

4. 上面的饼图通过聚合拥有最高内存引用(本身内存和总内存)的对象来展示 3 个问题嫌疑人。

让我们逐一分情况查看,评估它是否是内存溢出错误的根本原因。

可疑点 1

由 “” 加载的 454,570 个 “java.lang.ref.Finalizer” 实例占用了 790,205,576(47.96%)个字节。

这就是告诉我们有 454,570 个 JVM finalizer(终结器)实例占据了分配的应用内存的近 50 %。

假设读者知道 Java Finalizer 是做什么的,上面的信息会让我们明白什么呢?

入门阅读:http://stackoverflow.com/questions/2860121/why-do-finalizers-have-a-severe-performance-penalty

本质上,开发者编写了一些定制化的终结器去释放一个实例的资源。这些由终结器收集的实例不在 JVM 使用单独队列的垃圾回收算法的范围之内。实际上,这种途径比起垃圾回收机制的清理路径更长。所以现在我们应该努力搞清楚这些终结器到底终结了什么?

也或许是可疑点 2 ,占据了 20% 的 sun.security.ssl.SSLSocketImpl 。我们能确认是否这些就是要被终结器终结的实例吗?

可疑点 2

现在,让我们打开在 MAT 顶部的工具按钮下面的 Dominator 视图。我们会看到所有的列出的类实例,经由 MAT 解析展示出有效的堆存储。

f901a3014aa7b2edcbd0becccdef8b1f.png

下一步,在 Dominator 视图,我们尝试理解 java.lang.Finalizer 和 sun.security.ssl.SSLSocketImpl 之间的关系。我们右键点击 sun.security.ssl.SSLSocketImpl 这一列,打开 GC Roots -> exclude soft/weak references。

9d02c1907b9f633ac79b68ab3e464137.png

现在,MAT 将会开始绘制内存的图表来显示 GC root 的路径以及它所对应的实例引用。这会被显示在另外一个页面上,显示的引用如下:

ec71eb7f06a13989832b54bf5d4f76b4.png

如上面引用链显示,实例 SSLSocketImpl 来自于 java.lang.ref.Finalizer,整个 SSLSocketImpl 实例大约占用了 88k。我们还注意到 finalizer 链是一个针链表数据结构它指向下一个实例。

推论:在这一点上,我们有一个明确的感觉,Java finalizer 试图在收集 SSLSocketImpl 对象。为了解释为什么还有很多信息没有被收集到,我开始检查代码。

检查代码

代码检查需要查看是不是由 socket 套接字被关闭导致的。在这种情况下,它显示与 I/O 相关的所有流,需要被正确地关闭。在一点上,我们怀疑 JVM 是始作俑者。实际上,在 Open JDK 6.0.XX 的 GC(垃圾收集器)上的代码中有一个 BUG。

我希望这篇文章给你一个模式来分析 Java 应用中的错误是由堆存储还是内部问题导致的。希望你使用堆分析愉快!

扩展阅读

Shallow heap (浅堆) vs. Retained Heap (保留堆)

浅堆是一个对象消耗的内存。根据情况,一个对象需要 32 位或 64 位(取决于其操作系统架构),对于整型为 4 字节,对于 Long 型为 8 字节等等。依据堆转储格式,其内存大小(比如,向 8 对齐)或许适应于更好地塑造虚拟机的真实消耗。

X 的保留集合是当 X 被垃圾回收时,那些将要被移除的对象集合。

X 的保留堆是在 X 的保留集合中所有对象的浅堆之和,也就是 X 存留的内存。

总体讲,一个对象的浅堆就是其在堆中的大小。同一个对象的保留大小就是当对象被垃圾回收时堆内存的总量。

一些对象的主要集合,比如某一特定类的所有对象、或是由某一特定类加载器加载的所有类的所有对象、或仅仅是一些任意的对象,它们的保留集是如果那些主要集的所有对象变得不可接近时所释放的对象集。

保留集包括这些对象和仅通过这些对象才能获取的其它对象。保留集的大小是包含在保留集中的所有对象的堆的大小。

来自:开源中国 协作翻译

原文:Java Out of Memory Heap Analysis

链接:https://dzone.com/articles/java-out-of-memory-heap-analysis返回搜狐,查看更多

译者:dreamanzhao, 无若

程序员大咖整理发布,转载请联系作者获得授权

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值