Toggle Theme Editor
Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate Charcoal

The Structure Of Java Object -the Memory Layout-

Discussion in 'Java Update' started by Joe, 15/7/19.

  1. Joe

    Joe Thành viên VIP

    Do you know how to calculate the size of a Java Object? No? Normally every Java Developer knows the size of Java Primitives (long, int, double, etc.). However, there are still some confusion between the size of Java Primitives and Java Objects. This blog tries to clarify this nebulous size-problem (using JAVA standard API)


    PRIMITIVES
    Let's confer the size of Java Primitives:
    PHP:
    +------------------------+---------------+
    Primitive              Size in Bytes |
    +------------------------+---------------+
    double                 |      8        |
    Long                   |      8        |
    int                    |      4        |
    float                  |      4        |
    short                  |      2        |
    char                   |      2        |
    byte                   |      1        |
    boolean                |      1        |
    +------------------------+---------------+
    It's clear so far. BUT: what size a primitive has if it's used as an object? For example: Integer or Long? Because JAVA does not offer its users the similar C-Operator sizeof() JAVA Developers have to fumble around like the blind without a guide dog in order to get the size.

    JAVA SizeOf Implementation

    Because JAVA devs rarely confront the Size-Problem most of them are not aware about this API java.lang.instrument.Instrumentation. This API allows its users to determine the basic Memory Size of a Java Object. The implementation is a straight forward sequence of 3 following steps:

    1. The codes: SizeOf.java. This little API is used by JVM as JVM option which is initialized and instantiated before the invoking app is loaded and executed.
    PHP:
    import java.lang.instrument.Instrumentation;
    // Joe Nartca (C)
    public class SizeOf {
        private static 
    volatile Instrumentation instrument;
        public static 
    void premain(final String arg, final Instrumentation inst) {
            
    instrument inst;
        }
        public static 
    long objectSize(Object obj) {
            if (
    instrument != null) return instrument.getObjectSize(obj);
            throw new 
    IllegalStateException("Instrumentation is not initialized.");
        }
    }
    2. The Manifest file: manifest.mf. Note: the keyword Premain-class: [ name ]
    PHP:
    Manifest-Version1.0
    Permissions
    sandbox
    Created
    -ByJoe
    Premain
    -Class: SizeOf
    3. compile SizeOf.java and run the jar as following to create a jar-file sizeof.jar:
    PHP:
    jar -cvfm sizeof.jar manifest.mf SizeOf.class > o.txt
    If you've successfully done the 3 mentioned steps you can now run the sizeof.jar as the JVM-Option. For example: your app TestSizeOf uses the objectSize(Object obj) to determine the size.
    PHP:
    java -javaagent:sizeof.jar TestSizeOf
    TestSizeOf.java
    PHP:
    import java.util.*;
    public class 
    TestSizeOf {
     
      public static 
    void printObjectSize(Object object) {
        
    System.out.println("ObjectType: "+object.getClass()+"<>Size: "+SizeOf.objectSize(object)+" bytes");
      }
     
      public static 
    void main(String[] arguments) {
        
    TestSizeOf tso = new TestSizeOf();
      }
      public 
    TestSizeOf() {
        
    String empty = "";
        
    String string "This is a string";
        
    String[] stringArray = { empty, string"Joe Nartca" };
        
    String[] bigStringArray = new String[100];
        List<
    StringstringList = new ArrayList<>();
        
    StringBuilder stringBuilder = new StringBuilder(100);
        
    int maxIntPrimitive Integer.MAX_VALUE;
        
    int minIntPrimitive Integer.MIN_VALUE;
        
    Integer maxInteger Integer.MAX_VALUE;
        
    Integer minInteger Integer.MIN_VALUE;
        
    long zeroLong 0L;
        
    double zeroDouble 0.0;
        
    boolean falseBoolean false;
        
    Object object = new Object();
       
        
    EmptyClass emptyClass = new EmptyClass();
        
    StringClass stringClass = new StringClass();
        
    MixClass mixClass = new MixClass();
       
        
    printObjectSize(empty);
        
    printObjectSize(string);
        
    printObjectSize(stringArray);
        
    printObjectSize(bigStringArray);
        
    printObjectSize(stringList);
        
    printObjectSize(stringBuilder);
        
    printObjectSize(maxIntPrimitive);
        
    printObjectSize(minIntPrimitive);
        
    printObjectSize(maxInteger);
        
    printObjectSize(minInteger);
        
    printObjectSize(zeroLong);
        
    printObjectSize(zeroDouble);
        
    printObjectSize(falseBoolean);
        
    printObjectSize(object);
        
    printObjectSize(emptyClass);
        
    printObjectSize(stringClass);
        
    printObjectSize(stringClass);
      }
      
    //
      
    class EmptyClass {
      }
      class 
    StringClass {
        public 
    String s;
      }
      class 
    MixClass {
        
    int a// 4 bytes
        
    long b// 8 bytes
        
    float f// 4 bytes;
        
    double d// 8 bytes
        
    StringClass s;
      }
    }
    and the output:
    PHP:
    C:\java>java -javaagent:sizeof.jar TestSizeOf
    ObjectType
    : class java.lang.String<>Size24 bytes
    ObjectType
    : class java.lang.String<>Size24 bytes
    ObjectType
    : class [Ljava.lang.String;<>Size32 bytes
    ObjectType
    : class [Ljava.lang.String;<>Size4016 bytes
    ObjectType
    : class java.util.ArrayList<>Size24 bytes
    ObjectType
    : class java.lang.StringBuilder<>Size24 bytes
    ObjectType
    : class java.lang.Integer<>Size16 bytes
    ObjectType
    : class java.lang.Integer<>Size16 bytes
    ObjectType
    : class java.lang.Integer<>Size16 bytes
    ObjectType
    : class java.lang.Integer<>Size16 bytes
    ObjectType
    : class java.lang.Long<>Size24 bytes
    ObjectType
    : class java.lang.Double<>Size24 bytes
    ObjectType
    : class java.lang.Boolean<>Size16 bytes
    ObjectType
    : class java.lang.Object<>Size16 bytes
    ObjectType
    : class TestSizeOf$EmptyClass<>Size16 bytes
    ObjectType
    : class TestSizeOf$StringClass<>Size24 bytes
    ObjectType
    : class TestSizeOf$StringClass<>Size24 bytes
     
    C
    :\java>
    Size of Java Objects

    Probably you may surprise to see the sizes of the objects which are different, but some have the same size (e.g. 16 or 24). Why? Let me explain the JAVA Internals to you: Java Object has the following memory structure:
    PHP:
    +------------------------+-----------+
    Header (className)     | 8/12 bytes12 bytes by array (header+4 bytes int for the length)
    +------------------------+-----------+
    primitive              x byte(s) | 1248
    +------------------------+-----------+
    | (
    padding alignment)  | y byte(s) | if 1if 2etc8 bytes-alignment
    +------------------------+-----------+
    Reference (i.e.object) | 4 bytes   reference is here the pointer to other JAVA object
    +------------------------+-----------+
    | (
    padding alignment)  | n byte(s) | n is the rest of the sum of the above modulo 8
    +------------------------+-----------+
    JVM cares about the 8-bytes alignment so that the padding bytes between Primitive-Reference, Reference-Reference and the end of block are reduced to the minimum. Example:
    PHP:
    class MyObject {
        
    byte a;
        
    int c;
        
    boolean d;
        
    long e;
        
    Object f;       
    }
    The Memory Size of MyObject is:
    PHP:
    +------------------------+-----------+
    Header (className)     | 8 bytes   |  8
    +------------------------+-----------+
    e                      8         16
    +------------------------+-----------+
    c                      4         20
    +------------------------+-----------+
    a                      1         21
    +------------------------+-----------+
    d                      1         22
    +------------------------+-----------+
    padding                2         24 (8-bytes alignment)
    +------------------------+-----------+
    f                      4         28
    +------------------------+-----------+
    padding                4         32 (8-bytes alignment)
    +------------------------+-----------+
    PHP:
    class AnotherObject {
        
    byte a;
    }
    The Memory Size of MyObject is:
    PHP:
    +------------------------+-----------+
    Header (className)     | 8 bytes   |  8
    +------------------------+-----------+
    a                      1         |  9
    +------------------------+-----------+
    padding                7         16 (8-bytes alignment)
    +------------------------+-----------+
    With this knowledge we could deduce, for example Object Integer of primitive int:

    Interger (object of int)
    PHP:
    +------------------------+-----------+
    Header (className)     | 8 bytes   |  8
    +------------------------+-----------+
    int                    4         12
    +------------------------+-----------+
    padding                4         16 (8-bytes alignment)
    +------------------------+-----------+
    PHP:
        String[] stringArray = { empty, string"Joe Nartca" };
    PHP:
    +------------------------+-----------+
    Header (className)     | 12 bytes  12
    +------------------------+-----------+
    | empty 
    Reference        4         16
    +------------------------+-----------+
    string Reference       4         20
    +------------------------+-----------+
    padding                4         24 (8-bytes alignment)
    +------------------------+-----------+
    "Joe Nartca" Reference 4         28
    +------------------------+-----------+
    padding                4         32 (8-bytes alignment)
    +------------------------+-----------+
    Memory Size Calculation

    The API SizeOf give you only the base of memory structure of JAVA object, not the occupied memory size. To calculate the true memory size you have to work manually. Example:
    PHP:
        List< Integer IntList = new ArrayList< >(1000000);
        
    int[] intArray = new int[1000000];
        for (
    int i 01000000; ++i) {
          
    IntList.add(i);
          
    intArray[i] = i;
        }
     
    The output:
    PHP:
    ObjectType: class java.util.ArrayList<>Size24 bytes
    ObjectType
    : class [I<>Size4000016 bytes
    • IntList is an object ArrayList<Integer> with the base of 24 bytes. Each element is an Integer Object of 16 bytes. Together: MemorySize = 24 + 16*1000000 + 4*1000000 = 20000024 bytes or ~20 MB
    • intArray is an object of primitive-array: 12 + 4*1000000 + 4 End-Padding = 4000016 bytes or ~4 MB
    The sum of ArrayList< Integer > with 1000000 elements is as following:
    • Object ArrayList has 1 header, 2 int (size, capacity) and 1 reference (Object array) = 8 + 4 +4 + 4 + 4-padding 24 bytes
    • ObjectArray contains 1000000 Integer Objects = 1000000 references to Integer Objects = 1000000 * 4 = ~4 MB
    • Each Integer Object has 16 bytes = 1000000 * 16 = ~16 MB
    Together: 24 bytes + 16MB + 4 MB = ~20 MB.

    Have fun with JAVA Internals....
     
    Last edited: 17/7/19

Chia sẻ trang này

Loading...