【发布时间】:2013-01-15 19:38:23
【问题描述】:
在 Java 中,我想弄清楚一个对象在分配时使用的确切内存量。
仅仅调用构造函数和度量是行不通的,因为它可能会在构造函数期间分配其他对象。此外,我更喜欢使用实时计算给定 VM 中已用内存的方法。这可能不是标准的 VM,因此计算字段并做出明智的猜测是不够的。
无论如何,到目前为止,我发现您可以使用sun.reflect.ReflectionFactory 中的newConstructorForSerialization 创建一个没有其他分配的对象。
这可行,但不知何故,对 newInstance 的调用分配的内存块比预期的多。
例如类
public class a {
Integer a;
}
和
public class b {
Integer b = new Integer(12345);
}
两者都应该给出相同的结果。在这种情况下,在默认 VM 中使用 Java 7 时为 16 个字节。
但是,我的代码给出了 32 个字节(总是比预期多 16 个字节)。我可以通过从结果中删除 16 来弥补这一点,但我需要 100% 确定它总是分配那个额外的块。对我来说,知道内存使用的上限比确切的数量更重要。因此,如果我 100% 确定始终添加此块,则从结果中减去 16 才是安全的。
我的代码:(使用 -XX:-UseTLAB VM 参数运行)
import java.lang.reflect.Constructor;
import sun.reflect.ReflectionFactory;
public class test {
public static void main(String[] args) throws Exception {
prepare(a.class, Object.class);
System.out.println(memUse());
System.out.println(memUseSimple());
}
private static long memUseSimple() {
long start = Runtime.getRuntime().freeMemory();
a a = new a();
return start - Runtime.getRuntime().freeMemory();
}
private static long memUse() throws Exception {
Object o0 = intConstr.newInstance();
long start = Runtime.getRuntime().freeMemory();
Object o1 = intConstr.newInstance();
return start - Runtime.getRuntime().freeMemory() - 16;
}
private static Constructor<?> intConstr;
private static void prepare(Class<?> clazz, Class<?> parent) throws Exception {
intConstr = ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(clazz,
parent.getDeclaredConstructor());
return;
}
}
编辑:
澄清一下:我想知道为什么我需要减去 intConstr.newInstance() 调用的 16 字节开销,如果我可以 100% 确定这个开销总是相同的(或至少不少于 16 字节)。
即使在上面的代码中将 a 替换为 b,它仍然会给出 16 作为 memUse() 的结果,而不是 memUseSimple()。我只关心memUse(),但添加了简单的方法作为比较。
我知道intConstr.newInstance() 在另一个 VM 上可能有不同的开销。这并不重要,我需要知道的是,如果它在当前 VM 上产生 16 字节的开销,它是否总是会产生 16 字节的开销(在此运行时)?此外,与 new a() 相比,这种开销来自哪里?
【问题讨论】:
-
对象有开销。这是一个相关的问题:stackoverflow.com/questions/258120/…
-
尝试将你的init改成
new Integer(0);值 -128 到 127 被缓存,因此比较公平。 -
在计算内存使用之前你有没有调用GC?
-
另外,你怎么可能假设只有单个对象分配会反映在可用内存的变化中?
-
该代码应该适用于 32 位和 64 位 jvm。我注意到另一个使用 32 字节内存块的 jvm 的开销是 32 字节。