3

我的应用程序需要大约 10 GB 的 RAM 用于特定输入,而对于常规输入,大约 1 GB 就足够了。使用 JProfiler 进行更仔细的分析表明(在 GC 之后)标准类使用了相当多的内存java.util.*

LinkedHashMap$Entry, HashMap$Entry[], LinkedHashMap, HashMap$KeySet, HashMap$EntrySet, LinkedHashSet, TreeMap$Entry, 和TreeMap(按此顺序)和相关类。以下条目是我自己代码中的一个类,其中实例的数量和使用的内存量似乎非常合理。

在总堆使用量约为 900 MB 的情况下,我Size在视图中看到以下条目All Objects

  • LinkedHashMap$Entry: 418 兆字节
  • HashMap$Entry[]: 178 兆字节
  • LinkedHashMap:124兆字节
  • HashMap$KeySet: 15 兆字节

使用的内存LinkedHashMap似乎太高了,即使考虑到LinkedHashSeteach 由LinkedHashMap.

我在 JProfiler 中记录了对象分配并观察了Allocation Hot Spotsfor LinkedHashMap. 在那里,我看到了我不理解的条目:

  • 第三个条目显示了一个热点(分配内存的 6.5%),名为X.<init>whereX是我自己代码中的一个类。该方法的构造函数与 . 没有任何关系LinkedHashMap。在此进入到Thread.run最后显示从 6.5% 到 5.8% 的缓慢下降Thread.run。我的代码可能有什么问题X?为什么显示在这里?
  • 大约 8% 的已分配内存显示在名为 的热点中java.util.HashSet.iterator。沿着百分比最高的路径(第一个条目:2.8%)跟随这个条目,我在代码中得到了几个方法,直到最后java.lang.Thread.run显示(2.8%)。这是什么意思?据我所知,该Thread.run方法不会创建LinkedHashMap. 与iterator方法有什么关系?

一般来说,我如何找到保留对(很多)LinkedHashMap对象的引用的代码?使用 Heap Walker,我只能看到很多这样的实例,但看不到任何模式(即使在观察到 GC 根的路径时)。在我的实验中,所有实例似乎都井然有序。

可能重要的事情:

  • 我的应用程序构造了一个结果(用于进一步处理),并且对于这种构造,观察到了高内存使用情况。LinkedHashMap构造不断创建对象,因此不可能等待一个稳定点然后观察每个创建的对象。
  • 我有很好的计算机可供调试(最多 48 个内核和 192 GB 的 RAM,甚至可能更多)。
  • java 版本“1.7.0_13”(Java(TM) SE 运行时环境(构建 1.7.0_13-b20),Java HotSpot(TM) 64 位服务器 VM(构建 23.7-b01,混合模式))
  • JProfiler 7.2.2(内部版本 7157),许可
4

1 回答 1

5

一般来说,我如何找到保留对(很多)LinkedHashMap 对象的引用的代码?

在 heap walker 中,选择“LinkedHashMap”并创建一个新的对象集。然后切换到“参考”视图并显示“累积传入参考”。在那里,您可以分析整个对象集的引用。

在此处输入图像描述

至于您关于分配热点的问题以及为什么显示 Thread.run 方法:这些是回溯,它们显示了热点是如何被调用的,节点上的所有数字都是对顶部热点的贡献。最深的节点将始终是一个入口点,通常是 Thread.run 方法或 main 方法。

于 2013-02-19T09:59:14.760 回答