4

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.

  1. float (primitive)
  2. double (primitive)
  3. boolean (primitive)
  4. Float (Object)
  5. Double (Object)
  6. BigDecimal (Object)
  7. Boolean (Object)
  8. 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:

  1. Numbers output by sizeof.jar are in bytes.
  2. Either BigDecimal/Double/Float take crazy amounts of memory or there is a problem with the sizeof library.
  3. Sizeof seems to be reporting numbers that would make sense for primitive types
  4. object pointers on 64 bit machine are 8 bytes
  5. 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.
  6. 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:

  1. get sizeof jar from http://sizeof.sourceforge.net/
  2. add the sizeof.jar to the project/classpath
  3. add the javaagent for sizeof to server startup
  4. 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)
  5. I created several test classes to see the size of booleans. For instance TestPacked10Bool has 10 booleans.
  6. 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

Community
  • 1
  • 1
  • 3
    you could have used more text then this. – Algorithmist Aug 10 '13 at 15:18
  • 2
    thanks - was this a sarcastic comment? If so Im wondering why you bothered. – user2670668 Aug 10 '13 at 15:41
  • trying to write an efficient application and I need to know the sizes since it is a large amount of data. If double is 8 bytes and BigDecimal is 50 bytes then I need to weigh the pressision loss against memory usage. – user2670668 Aug 10 '13 at 15:43
  • `Booleans really should only need 1 bit to be stored so allocating 8 bytes for a single boolean would be a horrible waste.` I don't know if this is true – boxed__l Aug 10 '13 at 15:45
  • experimentally I found that the sizeOf library is probably way off. I created 1,000,000 big decimal objects and stuck them in a static variable. Jvisualvm shows the heap going up about 53MB so BigDecimal must be less than 53 bytes. – user2670668 Aug 10 '13 at 15:45
  • What ever data you want to "process" should have a minimum word size – boxed__l Aug 10 '13 at 15:45
  • for 64 bit I think its 64 bit? right? pls correct me if im wrong – boxed__l Aug 10 '13 at 15:46
  • booleans are true or false. Im saying that theoretially you would only need 1 bit since a bit has 2 states. Practically speaking though it looks like it every 8 booleans added will increment memory – user2670668 Aug 10 '13 at 15:46
  • Have you read [this](http://www.javaworld.com/javaqa/2003-12/02-qa-1226-sizeof.html) ? – boxed__l Aug 10 '13 at 15:52
  • yeah I think you are right that the word size in 64 bit windows is 64 bit so I think the minimum chunk of memory that can be created by java is 8 bytes. Its been a while since I took that college course =) – user2670668 Aug 10 '13 at 15:53
  • boxed - thanks that is a really good article and I had not seen it. brings up a good point that real memory usage will depend on the JVM used and how it aligns the data in memory. For instance some jvm might pack 8 booleans into a contiguous 8 byte section in memory. Other bad implementations might put each boolean in a separate 8 byte chunk and use 64 bytes. This complicates things since in the end just knowing the sizes of each object does not translate to how much memory it will take. For instance looks like if I add 1 boolean I can get away with 7 more and not pay any memory penalty. – user2670668 Aug 10 '13 at 16:18
  • Please try to use JOL tool from OpenJDK - it will give you more precise results http://openjdk.java.net/projects/code-tools/jol/ – Sergey Ponomarev Jul 14 '18 at 19:23

0 Answers0