我可以使用Instrumentation.getObjectSize测量内存中包含元素的List的大小吗?

时间:2019-01-12 18:52:51

标签: java instrumentation

据我所知java.lang.instrument.Instrumentation.getSize返回不带元素的大小(因为大小不取决于列表的数目。它是24个字节)。看起来很奇怪列表项未被测量是否正确?

1 个答案:

答案 0 :(得分:2)

Java中对象的大小是固定的,因为Java与C ++一样,是一种静态类型的语言。大小基本上与class文件中写入的内容相对应。由于class的文件布局是固定的,因此其大小也是固定的。

例如ArrayList的外观大致如下:

public class ArrayList implements List
{
    Object[] elementData;
    private int size;
}

任何 ArrayList实例的大小将是elementData(指向Object[]的指针),size({{ 1}})和开销。因此,大约有24种声音是正确的。

通常称为 浅尺寸

听起来像您想要的是 深尺寸 ,即列表 + 所引用的所有对象的尺寸 + 这些对象引用的所有对象,等等。

使用工具API不可能直接做到这一点,但是通过一些骇人的反射+工具,您也许可以得到它。基本思想是反映对象并在所有引用的对象上递归调用int,跳过循环引用。

大致情况:

getObjectSize()

用作:

public class DeepSizeCounter {
    private HashSet<Object> counted = new HashSet<>();
    private long size = 0;

    public long getSizeDeep(Object x) throws Exception {
        counted.clear();
        size = 0;
        computeSizeDeep(x);
        return size;
    }

    private void computeSizeDeep(Object x) throws Exception {
        if (x != null && !counted.contains(x)) {
            counted.add(x);
            size += instrumentation.getObjectSize(x);
            if (x.getClass().isArray()) {
                if (!x.getClass().getComponentType().isPrimitive())
                    for (Object y : (Object[]) x)
                        computeSizeDeep(y);
            } else {
                for (Field f : x.getClass().getDeclaredFields()) {
                    if (!f.getType().isPrimitive() && (f.getModifiers() & Modifier.STATIC) == 0) {
                        f.setAccessible(true);
                        computeSizeDeep(f.get(x));
                    }
                }
            }
        }
    }
}

请注意,这种方法是不可靠的,因为对象可能具有对无法自动区分的某些全局状态的反向引用,因此最终可能会计数太多的对象。另外,如果启用了访问控制,则long totalSize = new DeepSizeCounter().getSizeDeep(myList); 黑客将无法使用,您将无法计算任何非公开成员。