测量和监控大型 HashMap 的大小

测量或至少在一定程度上准确估计包含自定义对象的哈希映射的总内存消耗的最佳选择是什么?

背景:

我们的系统有多个内存存储(ConcurrentHashMap 的),其中包含 1K-200K 不同类型的对象。我们想定期监控这些的内存占用。

限制/期望:

我们无法承受频繁的 GC 或这些哈希映射的完整迭代,因为这会对延迟产生负面影响。据我所知,java中没有sizeof(),所以我们可以估计。

考虑这些选项:

有一个线程通过以下方式报告每个 hashmap 的内存使用情况:

  1. 使用 classmexer 之类的工具测量 X 类型对象的大小,并将其乘以哈希图的大小。这忽略了 hashmap 本身使用的内存,假设它与其内容相比相对较小。

  2. 创建另一个 hashmap,然后添加 N 个该类型的对象,测量其大小,然后推断该数字以接近完整大小。

  3. 外部测量,然后将其提供给地图。考虑 jmap 或类似的东西,但这不会是非常繁重的操作,因为它会测量 jvm 中的所有内容吗?

  4. 当我们将对象添加到 hashmap 时,获取堆大小的增量。不确定这是否可行,因为它是多线程的

  5. 还有其他很棒的选择吗?


慕妹3146593
浏览 126回答 2
2回答

慕慕森

首先,Alexey Shipilev(Oracle 的前 JVM 工程师,现在在 Redhat)发表了一篇很棒的文章,解释说这不是那么容易。Java 中的每个对象都有两个标头,它们的大小取决于平台或 jvm 以 ( UseCompressedOops) 开头的配置。然后是字段和对象本身之间的填充和对齐(8 字节对齐)。然后,存在 JVM 根本不显示的空间,因为它不能或确实需要。所有这些使得计算某个对象在堆中有多少大小变得有些困难;幸运的是JOL存在。它甚至还有很多样本......这是一个小例子,假设你有这样一个类:static class MyValue {&nbsp; &nbsp; private final int left;&nbsp; &nbsp; private final String right;&nbsp; &nbsp; public MyValue(int left, String right) {&nbsp; &nbsp; &nbsp; &nbsp; this.left = left;&nbsp; &nbsp; &nbsp; &nbsp; this.right = right;&nbsp; &nbsp; }}然后你创建一个HashMap:&nbsp; &nbsp; Map<String, MyValue> map = new HashMap<>();&nbsp; &nbsp; System.out.println("empty map = " + GraphLayout.parseInstance(map).totalSize());&nbsp; &nbsp; MyValue one = new MyValue(1, "one");&nbsp; &nbsp; System.out.println("one = " + GraphLayout.parseInstance(one).totalSize());&nbsp; &nbsp; map.put("one", one);&nbsp; &nbsp; System.out.println("map after one = " + GraphLayout.parseInstance(map).totalSize());&nbsp; &nbsp; MyValue two = new MyValue(1, "two");&nbsp; &nbsp; map.put("two", two);&nbsp; &nbsp; System.out.println("map after two = " +&nbsp;&nbsp; &nbsp; GraphLayout.parseInstance(map).totalSize());

倚天杖

如果我的理解是正确的,你想知道并发HashMap的大小。我认为,以下步骤可能会有所帮助。创建一个后台线程(不是前台)。使用 ByteArrayOutputStream 序列化并发 HashMap。使用 toByteArray() 获取字节数组。最后以 kb/mb 为单位计算大小。使用 Logger 记录大小。其他选项是使用像 JProfiler 这样的探查器来查看对象图及其大小。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java