Im trying to figure out the size of certain object types in java. My specific question is what are the sizes of the below objects/primitives on a 64 bit machine. Primarily I am concerned with BigDecimal - but the others would be good to know as well.
- float (primitive)
- double (primitive)
- boolean (primitive)
- Float (Object)
- Double (Object)
- BigDecimal (Object)
- Boolean (Object)
- object pointers
My research:
I have done some testing experimentally for different object sizes using the SizeOf library (http://sizeof.sourceforge.net/) and Im a bit disturbed with what I see for BigDecimal, Double, Float, Boolean. It is reporting the size as over 12,000 bytes for one object - which seems like it could not possibly be true. Either it is truely 12k bytes or the SizeOf library is not working correctly. I will try to confirm this using jvisualvm and post back later.
I did find another post in a different thread for BigDecimal but I dont know for sure if the answer is correct: Java BigDecimal memory usage?
Observations:
- Numbers output by sizeof.jar are in bytes.
- Either BigDecimal/Double/Float take crazy amounts of memory or there is a problem with the sizeof library.
- Sizeof seems to be reporting numbers that would make sense for primitive types
- object pointers on 64 bit machine are 8 bytes
- TestEmpty is a class with nothing in it. I created it for references. Not sure why it is reported as 16 bytes as I think it should be just 8.
- For the test classes I added to measure primitive sizes (TestDouble/TestFloat/etc) you need to remove 8 bytes from the number reported since SizeOf is really reporting the object pointer (TestFloat) plus the size of the primitive.
Booleans:
Booleans seem to be interesting and deserving of more analysis. It looks like they must get packed together and seem to really take 1 byte each. Im guessing when java reserves memory on a 64 bit system it can only allocate 8 bytes or more. Booleans really should only need 1 bit to be stored so allocating 8 bytes for a single boolean would be a horrible waste. So to compensate Im guessing java will pack 8 booleans into the 8 bytes of onsecutive memory. Every 8 booleans I add seem to increase the memory by 8 bytes. It would be more space efficient to store 64 bits in the 8 bytes but Im guessing processing those booleans would be slower as they would have to be unpacked and sent to the processors registers.
How I conducted my tests:
- get sizeof jar from http://sizeof.sourceforge.net/
- add the sizeof.jar to the project/classpath
- add the javaagent for sizeof to server startup
- sizeof only works for objects so to test the size of bool/float/doubles I created classes that just contain a single primitive variable (TestBool, TestDoubld, TestFloat, etc)
- I created several test classes to see the size of booleans. For instance TestPacked10Bool has 10 booleans.
- ran on a 64 bit system.
Here is the code for my tests:
public static void testObjectSizes()
{
List <Object> items = new ArrayList<Object>();
items.add(new BigDecimal(0));
items.add(new BigDecimal(1000000000));
items.add(new BigDecimal("1000000000"));
items.add(new BigDecimal("1000000000000000000000"));
items.add(new BigDecimal("1000000000.0000000001"));
items.add(new BigDecimal("1000000000000000000000.0000000001"));
items.add(new BigDecimal("1000000000000000000000.0000000000000000000001"));
items.add(new TestBigDecimal());
items.add(new Double(0));
items.add(new Double(1000000000));
items.add(new Float(0));
items.add(new Float(1000000000));
items.add(new TestDouble());
items.add(new TestEmpty());
items.add(new TestFloat());
items.add(new Boolean(true));
items.add(new TestBool());
items.add(new TestPacked2Bool());
items.add(new TestPacked3Bool());
items.add(new TestPacked4Bool());
items.add(new TestPacked5Bool());
items.add(new TestPacked6Bool());
items.add(new TestPacked7Bool());
items.add(new TestPacked8Bool());
items.add(new TestPacked9Bool());
items.add(new TestPacked10Bool());
items.add(new TestPacked11Bool());
items.add(new TestPacked12Bool());
items.add(new TestPacked13Bool());
items.add(new TestPacked14Bool());
items.add(new TestPacked15Bool());
items.add(new TestPacked16Bool());
items.add(new TestPacked17Bool());
items.add(new TestPacked64Bool());
for (int i = 0 ;i < items.size(); i++)
{
System.out.println("test " + i + " - " +items.get(i).getClass().getName() + " size:" + SizeOf.deepSizeOf(items.get(i)));
}
}
Output:
test 0 - java.math.BigDecimal size:12144
test 1 - java.math.BigDecimal size:12144
test 2 - java.math.BigDecimal size:12144
test 3 - java.math.BigDecimal size:12216
test 4 - java.math.BigDecimal size:12208
test 5 - java.math.BigDecimal size:12216
test 6 - java.math.BigDecimal size:12224
test 7 - com.george.test.info.TestBigDecimal size:12160
test 8 - java.lang.Double size:296
test 9 - java.lang.Double size:296
test 10 - java.lang.Float size:288
test 11 - java.lang.Float size:288
test 12 - com.george.test.info.TestDouble size:24
test 13 - com.george.test.info.TestEmpty size:16
test 14 - com.george.test.info.TestFloat size:16
test 15 - java.lang.Boolean size:320
test 16 - com.george.test.info.TestBool size:16
test 17 - com.george.test.info.TestPacked2Bool size:16
test 18 - com.george.test.info.TestPacked3Bool size:16
test 19 - com.george.test.info.TestPacked4Bool size:16
test 20 - com.george.test.info.TestPacked5Bool size:24
test 21 - com.george.test.info.TestPacked6Bool size:24
test 22 - com.george.test.info.TestPacked7Bool size:24
test 23 - com.george.test.info.TestPacked8Bool size:24
test 24 - com.george.test.info.TestPacked9Bool size:24
test 25 - com.george.test.info.TestPacked10Bool size:24
test 26 - com.george.test.info.TestPacked11Bool size:24
test 27 - com.george.test.info.TestPacked12Bool size:24
test 28 - com.george.test.info.TestPacked13Bool size:32
test 29 - com.george.test.info.TestPacked14Bool size:32
test 30 - com.george.test.info.TestPacked15Bool size:32
test 31 - com.george.test.info.TestPacked16Bool size:32
test 32 - com.george.test.info.TestPacked17Bool size:32
test 33 - com.george.test.info.TestPacked64Bool size:80