Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Point take less memory than Integer

Tags:

java

memory

I'm measuring the sizes of objects by checking how long their byte arrays are using ByteArrayOutputStream. When doing:

System.out.println(Utils.getObjectSize(new Integer(123123)));
System.out.println(Utils.getObjectSize(new Point(123, 123)));

They return 81 and 51.

I belive Point consists of two primitives but that doesn't seem to be the reason.

The code I for Utils.getObjectSize:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
objectStream.writeObject(object);
objectStream.close();
return byteStream.toByteArray().length;

EDIT:

I expressed myself wrong. I actually wanted to know why they take more size in the stream.

like image 833
Rob Fox Avatar asked May 09 '11 08:05

Rob Fox


3 Answers

To start with the strings java.lang.Integer, java.lang.Number and value appear in the serialization result for Integer. That should give a hint about why the serialization size is not very well correlated with the members of the object.

Here is some of the content of the resulting byte arrays listed: http://ideone.com/ragKZ

import java.awt.Point;
import java.io.*;

class Test {

    public static byte[] getBytes(Object object) throws IOException {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        ObjectOutputStream objectStream = new ObjectOutputStream(byteStream);
        objectStream.writeObject(object);
        objectStream.close();
        return byteStream.toByteArray(); 
    }

    public static void main(String[] args) throws IOException {

        byte[] iBytes = getBytes(new Integer(123123));
        System.out.println(new String(iBytes,  8, 17)); // "java.lang.Integer"
        System.out.println(new String(iBytes, 39,  5)); // "value"
        System.out.println(new String(iBytes, 48, 16)); // "java.lang.Number"
        // ...

        byte[] pBytes = getBytes(new Point(123, 123));
        System.out.println(new String(pBytes, 8, 14));  // "java.awt.Point"
        // ...
    }
}
like image 119
aioobe Avatar answered Nov 01 '22 17:11

aioobe


Your approach for finding the size of objects doesn't actually measure how much space they take up in memory at all.

Point will actually take more memory than Integer (for a 4-byte-aligned JVM; with 8 byte alignment they'll be the same) - it just happens to serialize to a smaller size, probably due to the inheritance hierarchy.

like image 7
Jon Skeet Avatar answered Nov 01 '22 17:11

Jon Skeet


Integer is larger to serialise because its parent Number is Serializable. If you print all the text bytes in the object serialisation you get

....sr..java.lang.Integer.......8...I..valuexr..java.lang.Number...........xp....

However, Point's parent is not Serializable and is not serialized.

....sr..java.awt.Point...r4~.&...I..xI..yxp...{...{

Also Integer's field name is longer (slightly)

byte[] bytes = byteStream.toByteArray();
for(int i=0;i<bytes.length;i++) {
    char ch = (char) bytes[i];
    if (ch >= ' ' && ch < 127)
        System.out.print(ch);
    else
        System.out.print('.');
}
System.out.println();

The method you are using looks at how large is the Object serialisation as a byte[], not how large it is in memory. The standard Java serialisation is not very efficient.

Integer is likely to consume 16 + 4 bytes and Point is likely to consume 16 + 2 * 4 bytes. However as many JVMs allocate on a 8 byte boundary, you are likely to find they consume the same amount of memory.

The reason Integer is larger to serialize is that Java serializes not just the Object but its parents as well including listing what they are.

like image 5
Peter Lawrey Avatar answered Nov 01 '22 19:11

Peter Lawrey