I'm trying to figure out how Java structures/allocates memory for objects. (Yes this is implementation specific. I'm using the Oracle 1.7 runtime for this.) I did some work on this here and here and the results are confusing.
First off, in both referenced links, when I allocated an array of objects, the equivalent of new Object, it used 4 bytes per object. On a 32-bit system this makes perfect sense. But I'm on a 64-bit system so what's going on here?
Second, I compared the memory footprint of 8 booleans vs. a byte as the variables in a class. The 8 booleans requires 24 bytes/object or 3 bytes/boolean. The single byte approach requires 10 bytes/object.
And in the case of different ways to create a RGB class it gets really weird.
Any guidance as to what is going on here is appreciated. I have a couple of classes that get allocated a lot and the flywheel pattern won't work (these objects have their values changed all over the place).
And an associated question, does the order of declaring variables matter? Back in the old days when I did C++ programming, declaring "int, byte, int, byte" used 4 int's work of space while "int, int, byte, byte" used 3.
thanks - dave
64-bit Java can address a 64-bit memory range, but that doesn't necessarily mean a reference takes 64 bits because so called compressed oops (ordinary object pointers) may be used.
When you measured the size of objects did you take the object overhead into account? It's about 16 byte per object and if the object is an array you have to add 4 bytes to that to account for the array size.
Generally a boolean which is stored in an object will be stored as a byte, whereas in a method it will be stored as an int. If I recall correctly this is specified somewhere in the JVM specification.
Now to minimize storage there are two main strategies, reducing the number of objects to get rid of object overhead, and storing information in a more compact form. This may be contrary to good design of course so it's a tradeoff situation. The Flyweight design patterns can be used to lessen the negative consequences of this.
In one example you had a class with 8 booleans. This will take 8 bytes to store. If you instead use the individual bits of a byte to store the same amount of information it's an 8-fold reduction of space. If you use a getter method (which you should anyway) this change won't even be noticed from the outside.
But you still have the object overhead and it's enormous in relation to the information content in this case. To get rid of it you need to get rid of the objects and one way in this case is to instead store the bytes directly in a byte array (rather than storing objects holding the bytes). It'a a 16-fold reduction of space. The drawback is that the information no longer is identified by object references but by numbers (array entries). Either one simply accepts this or use the Flyweight pattern to make the numbers appear as object references.
or use the Flyweight pattern
One common Flyweight approach when the number of possible different objects of a class is very small is to use a set of shared immutable objects. This approach is used for example to represent small Integers in Java. If you do this,
Integer i1 = 42;
Integer i2 = 42;
you'll notice that i1 and i2 in fact hold the same reference. It's because the boxing conversion fetches small Integer objects (in the -127 to 128 range) from a table rather than creating them using new (as it does when the Integer is outside that range).
You could use the same approach in your case with the class holding 8 informative bits in a byte. There are just 256 such bytes so all possible objects can be created in advance and held in a table. When a certain bit combination is wanted no new object is created using new. Instead the appropriate object is picked from the table.
But note that for this to work the class holding the byte must be immutable. Objcts may not be changed after creation just like Integer objects can't.