A couple of months ago I was curious how much memory a new class I wrote would take. I lost my notes with the specifics but here's a high level overview of estimating class memory size.
First, a brief word of the Java Virtual Machine, in particular the Sun HotSpot VM. The HotSpot VM has three heap spaces for the three generations it manages: the young, old (tenured) and permanent. Yes, the permanent generation is part of the total heap the virtual machine manages. Many tools refer to the perm gen as non-heap, and while the -Xmx and -Xms don't affect the perm gen heap, it's nevertheless part of the total heap the virtual machine manages. You can control the permanent generation's heap size with the -XX:MaxPermSize option. Running the jmap utility lets you see the various heaps the virtual machine is managing.
So how does a class use up the heap spaces in the VM? When the virtual machine loads a class it create a klass (or is it klazz?) to define the class. This class definition eats into the permanent generation. A class with constants and lots of methods (more bytecode) will require more memory in the perm gen. The good news is there's only a single copy of the class definition. For the most part, unless you're generating classes at runtime and doing other advance things, you can largely ignore your class' s impact on the perm gen until you see those PermGen out of memory exceptions. But it's still important to understand how a class affects the perm gen. Incidentally, I think there's some work about an "invoke dynamic" instruction that'll allow you to execute arbitrary code without the need to define a class and use up the perm gen.
Most developers are more interested in how their classes affect the young and old generations. Here, we're really talking about objects and not classes. And here, application behavior is really important, because application behavior will largely dictate how much memory your objects take up.
Each object eats up a minimal amount of memory (overhead). Beyond this, instance member variables increase an object's size. For example,
SmallClass {
private String s1;
private void doNothing() {
// no-op
}
}BigClass {
private String s1;
private String s2;
private void doSomething() {
// a bunch of bytecode that eats up the perm gen heap
int i = 10;
for (int j =0 ; j < i; j++) {
// a bunch of code
}
}
}
BigClass requires 4 more bytes than SmallClass befcause of the s2 String. A reference is 4 bytes on my Linux 32-bit box running Java 5. If you run a "size of" on SmallClass and BigClass you might see that they are the same size, but that's because the VM has 8 byte alignment. Add another reference to BigClass (String s3, for example) and you'll see the size jump 8 bytes.
So far we've discussed the the "static" aspects of class and object memory sizes. Presumably, your strings will not be null and hold some value. Your object size will then depend on how big your strings are, i.e., how big the char arrays are (ignore string interning for the moment). Likewise, a reference to a HashMap is 4 bytes, but if the HashMap contains a million entries...This "deep" size obviously depends on the behavior of your application.
In Summary, the following is how a class eats up memory
- class definition ---> perm gen heap space
- object overhead + references ---> young/old gen heap space, multiply by how many objects
- object "deep size" ---> memory required by object beyond just the references (how long are the strings, how many entries in the map, how big are the arrays, etc.)
I have a mini-toolkit here: http://www.csd.uoc.gr/~andreou/monitoringtools.html
With which you can find out the memory footprint of an object (/object-graph).
About classes, I seem to vaugely remember that even the most trivial was about 200-250 bytes, but this may have changed a lot.
Posted by: Dimitris Andreou | April 27, 2009 at 01:32 AM
That was quite simple and clear, thank you.
Posted by: hotspot user | July 22, 2009 at 05:27 AM