测量和监视大型HashMap的大小

时间:2019-05-15 17:58:19

标签: java memory memory-management jvm

通过保存自定义对象的哈希图测量或至少在某种程度上准确估计总内存消耗的最佳选择是什么?

背景:

我们的系统有多个内存存储(ConcurrentHashMap's),其中存储着不同类型的1K-200K对象。我们希望定期监视这些内存的占用空间。

约束/期望:

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

考虑以下选项:

有一个线程通过以下方式报告每个哈希图的内存使用情况#

  1. 使用类似classmexer的方法测量类型X的对象的大小,然后将其乘以hashmap的大小。假设哈希表与其内容相比相对较小,它将忽略哈希表本身使用的内存。
  2. 创建另一个哈希图,然后添加该类型的N个对象,测量其大小,然后外推数字以近似整个大小。
  3. 从外部进行测量,然后将其输入到地图。考虑到jmap或类似的东西,但是这不会很繁琐,因为它可以测量jvm中的所有内容?
  4. 在将对象添加到哈希图中时,获取堆大小的增量。不知道这是否可行,因为它是多线程的
  5. 还有其他很棒的选择吗?

2 个答案:

答案 0 :(得分:2)

首先,有this(Alexey Shipilev)(甲骨文公司前JVM工程师,现为Redhat的一名出色文章)解释说,这不是那么容易。

>

Java中的每个对象都有两个标头,它们的大小可以取决于平台或jvm以(UseCompressedOops开始的配置。

然后,在字段和对象自身之间进行填充和对齐(8字节对齐)。然后,有一个JVM根本不会显示的空间,因为它不能显示或确实需要显示。

所有这些事情使得计算某个对象在堆中的大小变得有些微不足道。幸运的是JOL存在。它甚至也有很多示例...这是一个小示例,假设您有这样的类:

static class MyValue {

    private final int left;
    private final String right;

    public MyValue(int left, String right) {
        this.left = left;
        this.right = right;
    }
}

然后您创建一个HashMap

    Map<String, MyValue> map = new HashMap<>();
    System.out.println("empty map = " + GraphLayout.parseInstance(map).totalSize());

    MyValue one = new MyValue(1, "one");
    System.out.println("one = " + GraphLayout.parseInstance(one).totalSize());

    map.put("one", one);
    System.out.println("map after one = " + GraphLayout.parseInstance(map).totalSize());

    MyValue two = new MyValue(1, "two");
    map.put("two", two);
    System.out.println("map after two = " + 
    GraphLayout.parseInstance(map).totalSize());

答案 1 :(得分:1)

如果我的理解是正确的,那么您想知道并发HashMap的大小。我认为,以下步骤可能会有所帮助。

  1. 创建一个后台线程(不是前台线程)。
  2. 使用ByteArrayOutputStream序列化并发HashMap。
  3. 使用toByteArray()获取字节数组。
  4. 最后以kb / mb为单位计算大小。
  5. 使用Logger记录大小。

其他选项是使用Profiler之类的JProfiler来查看对象图及其大小。