【发布时间】:2013-02-19 09:33:43
【问题描述】:
我的应用程序需要大约 10 GB 的 RAM 用于特定输入,而对于常规输入,大约 1 GB 就足够了。使用 JProfiler 进行更深入的分析表明(在 GC 之后)java.util.* 的标准类使用了相当多的内存:
LinkedHashMap$Entry、HashMap$Entry[]、LinkedHashMap、HashMap$KeySet、HashMap$EntrySet、LinkedHashSet、TreeMap$Entry、TreeMap$Entry、TreeMap(按此顺序)以及相关类。以下条目是我自己代码中的一个类,其中实例的数量和使用的内存量似乎非常合理。
在总堆使用量约为 900 MByte 的情况下,我在 All Objects 视图中看到以下 Size 条目:
-
LinkedHashMap$Entry: 418 兆字节 -
HashMap$Entry[]: 178 兆字节 -
LinkedHashMap: 124 兆字节 -
HashMap$KeySet:15 兆字节
LinkedHashMap 使用的内存似乎太高了,即使考虑到每个LinkedHashSet 都由LinkedHashMap 支持。
我在 JProfiler 中记录了对象分配,并观察了 Allocation Hot Spots 的 LinkedHashMap。在那里,我看到了我不理解的条目:
- 第三个条目显示了一个名为
X.<init>的热点(分配了6.5% 的内存),其中X是我自己代码中的一个类。该方法的构造函数与LinkedHashMap没有任何关系。在最后进入Thread.run之后,在Thread.run处显示从 6.5% 缓慢下降到 5.8%。我在X中的代码可能有什么问题?为什么会显示在这里? - 大约 8% 的已分配内存显示在名为
java.util.HashSet.iterator的热点中。沿着百分比最高的路径(第一个条目:2.8%)跟随这个条目,我在我的代码中得到了几个方法,直到最后显示java.lang.Thread.run(2.8%)。这是什么意思?据我所知Thread.run方法不会创建LinkedHashMap的实例。与iterator方法有什么联系?
一般来说,我如何找到保留对(大量)LinkedHashMap 对象的引用的代码?使用 Heap Walker,我只能看到 lots 这些实例,但看不到任何模式(即使在观察到 GC 根的路径时)。在我的实验中,所有实例似乎都井然有序。
可能重要的事情:
- 我的应用程序构造了一个结果(用于进一步处理),并且对于此构造,观察到高内存使用率。该构造不断创建对象,因此不可能等待一个稳定点然后观察每个创建的
LinkedHashMap对象。 - 我有很好的计算机可供调试(最多 48 个内核和 192 GB RAM,可能更多)。
- java 版本 "1.7.0_13" (Java(TM) SE Runtime Environment (build 1.7.0_13-b20), Java HotSpot(TM) 64 位服务器 VM(内部版本 23.7-b01,混合模式))
- JProfiler 7.2.2(内部版本 7157),许可
【问题讨论】:
标签: jprofiler