In Java, I want to figure out the exact amount of memory a object uses while allocated.
Just calling the constructor and measure won't work, as it might allocate other object during the constructor. Also, I prefer to use a method that realtime calculate used memory in the given VM. This might not be the standard VM so counting fields and making a smart guess is not sufficient.
Anyway, so far I found that you can make a object with no other allocations with the newConstructorForSerialization
found in sun.reflect.ReflectionFactory
.
This works, but somehow the call to newInstance allocate 1 block of memory more then expected.
For example, the class
public class a {
Integer a;
}
and
public class b {
Integer b = new Integer(12345);
}
Should both give the same result. 16 bytes in this case using Java 7 in the default VM.
However, my code gives 32 bytes (always 16 more then expected). I can compensate for this by removing 16 from the result, but I need to be 100% sure it always allocate that additional block. It's more important for me to know the upped bound of memory usage then the exact amount. So it's only safe to subtract 16 from the result if I'm 100% sure this block is always added.
My code: (run with -XX:-UseTLAB VM arguments)
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;
}
}
Edit:
To clarify: I want to know why i need to subtract the 16 bytes overhead of the intConstr.newInstance()
call, and if i can be 100% sure this overhead is always the same (or at least not less then 16 bytes).
Even if you replace a with b in the above code, it still gives 16 as the result for memUse()
, but not memUseSimple()
. I only care about memUse()
but added the simple method as a comparison.
I know intConstr.newInstance()
can have a different overhead on another VM. This is not important, what i need to know if that if it gives a overhead of 16 bytes on the current VM, will it always give 16 bytes overhead (during this runtime)? Also, where does this overhead come from compared to just new a()
?