You define fields, their names and types, in source of Java class, but it is JVM the one who decides how they will be stored in physical memory.
Sometimes you want to know exactly how much Java object weights in Java. Answering this question is surprisingly complicated.
Challenge
- Pointer size and Java object header size varies.
- JVM could be build for 32 or 64 bit architecture.
On 64 bit architectures JVM may or may not use compressed pointers (
-XX:+UseCompressedOops
). - Object padding may be different (
-XX:ObjectAlignmentInBytes=X
). - Different field types may have different alignment rules.
- JVM may reorder fields in object layout as it likes.
Figure below illustrates how JVM may rearrange fields in memory.
Guessing object layout
You can scrap class fields via reflection and try to guess layout chosen by JVM taking into account platform pointer size and other factors.
... at least you can try.
Using the Unsafe
sun.misc.Unsafe is internal helper class used by JVM code. You should not use it, but you can (with some help from reflection). Unsafe is popular among people doing weird things with JVM.
Unsafe can let you query information about physical layout of Java object. Though, it would not tell you directly real size of object in memory. You would still have to do some error-prone math to calculate object's size.
Instrumentation agent
java.lang.instrument.Instrumentation is an API for profilers and other performance tools. You need to install agent into JVM to get instance of this class. This class has handy getObjectSize(...)
method which would tell you real object size.
There is library jamm which exploit this option. You should use special JVM start options though.
Threading MBean
Threading MBean in JVM has a handy allocation counter. Using this counter you can easily measure object size by allocating new instance and checking delta of counter. Snippet below is doing just that.
import java.lang.management.ManagementFactory;
public class MemMeter {
private static long OFFSET = measure(new Runnable() {
@Override
public void run() {
}
});
/**
* @return amount of memory allocated while executing provided {@link Runnable}
*/
public static long measure(Runnable x) {
long now = getCurrentThreadAllocatedBytes();
x.run();
long diff = getCurrentThreadAllocatedBytes() - now;
return diff - OFFSET;
}
@SuppressWarnings("restriction")
private static long getCurrentThreadAllocatedBytes() {
return ((com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean()).getThreadAllocatedBytes(Thread.currentThread().getId());
}
}
Below is simple usage example
System.out.println("size of java.lang.Object is "
+ MemMeter.measure(new Runnable() {
Object x;
@Override
public void run() {
x = new Object();
}
}));
Though, this approach require you to create new instance of object to measure its size. That may be an obstacle.
jmap
jmap
is a one of JDK tools. With jmap -histo PID
command you can print histogram of your heap objects.
num #instances #bytes class name
---------------------------------------------
1: 1413317 111961288 [C
2: 272969 39059504 <constMethodKlass>
3: 1013137 24315288 java.lang.String
4: 245685 22715744 [I
5: 272969 19670848 <methodKlass>
6: 206682 17868464 [B
7: 29355 17722320 <constantPoolKlass>
8: 659710 15833040 java.util.HashMap$Entry
9: 29355 12580904 <instanceKlassKlass>
10: 105637 12545112 [Ljava.util.HashMap$Entry;
11: 170894 11797400 [Ljava.lang.Object;
For objects, you can divide byte size by instance count to get individual instance size for class. This would not work for arrays, though.
Java Object Layout tool
Java Object Layout tool is using number of different approaches for introspecting physical layout of Java object in memory.