在 Java 中,我想弄清楚一个对象在分配时使用的确切内存量。
仅仅调用构造函数和度量是行不通的,因为它可能会在构造函数期间分配其他对象。此外,我更喜欢使用实时计算给定 VM 中已用内存的方法。这可能不是标准的 VM,因此计算字段并做出明智的猜测是不够的。
无论如何,到目前为止,我发现您可以使用newConstructorForSerialization
在sun.reflect.ReflectionFactory
.
这可行,但不知何故,对 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 字节的开销(在此运行时)?此外,与 just 相比,这种开销来自哪里new a()
?