Insider Analysis on Java object size

Source: Internet
Author: User

Insider Analysis on Java object size

In a recent whim, I suddenly became interested in the memory size of Java objects. I collected some information on the Internet and sorted it out. I hope you can help me.
If: you can calculate the memory size occupied by the new String ("abc") object in the JVM (64-bit JDK7 compressed size of 48 B, not compressed size of 64 B ), so we can end it here ~

Memory layout of Java objects: Object headers, Instance Data, and Padding).
The virtual machine object header contains two parts. The first part is usedStores the runtime data of an object., Such as hashCode, GC generational age, lock status mark, lock held by the thread, biased thread ID, biased timestamp, etc. The length of this part of data is 4B and 8B in 32-bit and 64-bit virtual machines (pointer compression is not enabled), which are officially referred to as "Mark Word ".
Another part of the object isType pointer (kclass)That is, the pointer to the class metadata of the object. The VM determines through this pointer that the object is an instance of that class. In addition, if the object is a Java array, there must be a piece of data in the object header to record the length of the array, because the virtual machine can determine the size of the Java object through the metadata information of the common Java object, however, the array size cannot be determined from the array metadata.
The object header occupies 8B on a 32-bit system and 16B on a 64-bit system. Both 32-bit and 64-bit systems use 8-byte alignment. Java enables pointer compression in 64-Bit mode. In 32-Bit mode, the header is larger than 4B (the mark area is changed to 8B and the kclass area is compressed). If pointer compression is not enabled, the header will be large 8B (both mark and kclass are 8B)In other words,
? The hot spot alignment mode is 8-byte alignment: (Object Header + instance data + padding) % 8 equals 0 and 0 <= padding <8. The following descriptions are based on HotSpot.

As mentioned in reference 2, java. lang. instrument. Instrumentation provided after JDK 5 provides a wide range of tracking and object size measurement APIs for structures and other aspects. However, this item can be used only by using the java agent. As for agent and Instrumentation, I will not describe it here. I will only describe how to use it here.
This class is provided in Reference 3, and I personally think it is very practical. The code is shown in the appendix 1 below (the code is long and the flexibility is put at the end of the article ):
This code can be copied directly and then packaged into a jar package (named "agent. jar, if the package is not successful, you can directly download the main blog package), pay attention to the META-INF/MANIFEST. add a row to MF:

Premain-Class: com. zzh. size. MySizeOf (note ":" is followed by a space. Otherwise, an error is returned: invalid header field .)

For example, the Code is as follows (the blogger's system is 64-bit and uses 64-bit JDK7 ):

import com.zzh.size.MySizeOf;public class ObjectSize{    public static void  main(String args[])    {        System.out.println(MySizeOf.sizeOf(new Object()));    }}

Next, compile and run the program as follows:

Compile (agent. jar in the current directory): javac-classpath agent. jar ObjectSize. java running: java-javaagent: agent. jar ObjectSize (output result: 16. For the analysis of this result, I will explain it later)

JDK6 introduces the parameter-XX: + UseCompressedOops. this parameter is automatically enabled in 32 GB memory by default. You can add-XX:-UseCompressedOops to the running parameters to disable pointer compression.
You can use Instrumentation to test the object size to better indicate the size of an object. In fact, you can manually calculate the size of an object when it is created, code case practices are used to prove the rationality and correctness of theoretical knowledge. The specific algorithms are embodied in the following code cases.

Supplement: the memory usage of the native type is as follows:

Primitive Type Memory Required (bytes)
Boolean 1
Byte 1
Short 2
Char 2
Int 4
Float 4
Long 8
Double 8

The reference type occupies 4B for each 32-bit system and 8B for each 64-bit system.

Case Analysis
After reading so many cases, I guess it is very mysterious. I will use several code cases to practice it.

Case 1: The size of the new Object () above is 16 B. I would like to reiterate that the master testing machine is a 64-bit JDK 7. If no special instructions are provided, pointer compression is enabled by default.

New Object () size = Object Header 12B (8Bmak, 4Bkclass) + padding 4B = 16B

Case 2:

    static class A{        int a;    }    static class B{        int a;        int b;    }    public static void  main(String args[])    {        System.out.println(MySizeOf.sizeOf(new Integer(1)));        System.out.println(MySizeOf.sizeOf(new A()));        System.out.println(MySizeOf.sizeOf(new B()));    }

Output result:

(Pointer compression) 16 16 24 (pointer not compressed) 24 24 24

Analysis 1 (pointer compression ):

Size of new Integer (1) = 12B object header + instance data of 4B + fill of 0B = 16 Bnew () size = 12B object header + 4B instance data + 0B filling = 16 Bnew B () size = 12B object header + 2 * 4B instance data = 20B, after filling = 24B

Analysis 2 (pointer uncompressed ):

Size of new Integer (1) = 16B object header + instance data of 4B + fill of 4B = 24 Bnew () size = 16B object header + 4B instance data + 4B filling = 24 Bnew B () size = 16B object header + 2 * 4B instance data + 0B filling = 24B

Case 3

System.out.println(MySizeOf.sizeOf(new int[2]));System.out.println(MySizeOf.sizeOf(new int[3]));System.out.println(MySizeOf.sizeOf(new char[2]));System.out.println(MySizeOf.sizeOf(new char[3]));

Output result:

(Pointer compression) 24 32 24 24 (pointer uncompressed) 32 40 32 32

Analysis 1 (pointer compression ):

The size of new int [2] = 12B object header + in case of compression, the array is more 4B than the normal object to store the length + 2 * 4B int instance size = 24 Bnew int [3] size = 12B object header + 4B Length + 3 * 4B int instance size = 28B, fill in 4B = 32 Bnew char [2] size = 12B object header + 4B Length + 2 * 2B instance size = 20B, fill 4B = 24 Bnew char [3] size = 12B object header + 4B Length + 3 * 2B instance size + 2B fill = 24B (PS: size of new char [5] = 32B)

Analysis 2 (pointer uncompressed ):

The size of new int [2] = 16B object header + the size of an array is larger than that of an ordinary object in the case of uncompressed 8B to store the length + 2 * 4B instance size = 32 Bnew int [3] = 16B + 8B + 3 * 4B + 4B fill = 40 Bnew char [2] size = 16B + 8B + 2 * 2B + 4B fill = 32 Bnew char [2] size = 16B + 8B + 3 * 2B + 2B fill = 32B (PS: the size of new char [5] Is 40B)

Case 4(SizeOf only calculates the size of the ontology object. fullSizeOf calculates the size of the ontology object and the reference size. For details, refer to the Code in Appendix 1 ).

System.out.println(MySizeOf.sizeOf(new String("a")));System.out.println(MySizeOf.fullSizeOf(new String("a")));System.out.println(MySizeOf.fullSizeOf(new String("aaaaa")));

Output result:

(Pointer compression) 24 48 56 (pointer uncompressed) 32 64 72

Analysis 1 (pointer compression ):

You can refer to the source code of String (JDK7). String has these member variables: (static variables belong to Classes and do not belong to instances. Therefore, declared static variables are not included in the object size) private final char value []; private int hash; private transient int hash32 = 0; MySizeOf. sizeOf (new String ("a") size = 12B object header + 2 * 4B (member variables hash and hash32) + 4B (compressed value pointer) = 24BMySizeOf. fullSizeOf (new String ("a") size = 12B object header + 2 * 4B (member variables hash and hash32) + 4B pointer + (value array size = 12B object header + 4B array Length + 1 * 2B instance size + 6B fill = 24B) = 12B + 8B + 4B + 24B = 48B (PS: new String ("aa"), new String ("aaa"), new String ("aaaa ") the fullSizeOf value is 48B) MySizeOf. fullSizeOf (new String ("aaaaa") size = 12B + 2 * 4B + 4B + (12B + 4B + 5 * 2B + 6B filling) = 24B + 32B = 56B

Analysis 2 (pointer uncompressed)

MySizeOf. sizeOf (new String ("a") size = 16B + 2 * 4B + 8B (bit compressed pointer size) = 32BMySizeOf. fullSizeOf (new String ("a") size = 16B object header + 2 * 4B (member variables hash and hash32) + 8B pointer + (value array size = 16B object header + 8B array Length + 1 * 2B instance size + 6B fill = 32B) = 32B + 32B = 64B (PS: new String ("aa"), new String ("aaa"), the fullSizeOf size of new String ("aaaa") is 64B) MySizeOf. fullSizeOf (new String ("aaaaa") size = 16B + 2 * 4B + 8B + (16B + 8B + 5 * 2B + 6B filling) = 32B + 40B = 72B

These computation results will be less and less, because some object headers will stretch during code execution, and some external space will be referenced in the mark area (lightweight lock, biased lock, this is not shown here), so the official explanation is also, the minimum number of bytes will be occupied. It is definitely not the number of bytes occupied.

If it is a 32-bit JDK, you can calculate or run the results of the above cases.

We can manually calculate the size of new String () as shown in the preceding figure:
1. pointer Compression

12B object header + 2 * 4B instance variable + 4B pointer + (12B object header + 4B array Length Size + 0B instance size) = 24B + 16B = 40B
Pointer uncompressed
16B + 2 * 4B + 8B pointer + (16B + 8B array Length Size + 0B) = 32B + 24B = 56B

Therefore, an empty String object occupies at least 40 B of size, so you should pay attention to it later. In fact, I do not care too much. I believe that there are tens of thousands of people typing code from the beginning of the article. If you don't care about this, there is nothing wrong with it, however, if you understand it, it will be of great help to improve your code and optimization level. For example, it is best not to use its packaging class for basic types.

Appendix: source code of the agent. jar package

Package com. zzh. size; import java. lang. instrument. instrumentation; import java. lang. reflect. array; import java. lang. reflect. field; import java. lang. reflect. modifier; import java. util. arrayDeque; import java. util. deque; import java. util. hashSet; import java. util. set; public class MySizeOf {static Instrumentation inst; public static void premain (String args, Instrumentation instP) {inst = instP;}/*** directly calculates the space occupied by the current object, including the basic instance field size of the current class and super class, * Reference size of the Instance field of the reference type, total occupied space of the Instance basic type array, and occupied space of the Instance reference type array reference itself; * However, this does not include the size of the objects inherited by the superclass and the instance reference fields of the current class declaration, and the size of the objects referenced by the instance reference array. ** @ param obj ** @ return * /public static long sizeOf (Object obj) {return inst. getObjectSize (obj);}/*** recursively calculates the total space occupied by the current object, including the instance field size of the current class and super class and the size of the Instance field reference Object ** @ param objP * @ return * @ throws IllegalAccessException */public static long fullSizeOf (Object objP) throws IllegalAccessException {SetVisited = new HashSet(); DequeToBeQueue = new ArrayDeque <> (); toBeQueue. add (objP); long size = 0L; while (toBeQueue. size ()> 0) {Object obj = toBeQueue. poll (); // when sizeOf is specified, it indicates the basic type and reference length, including the array size + = skipObject (visited, obj )? 0L: sizeOf (obj); Class
     TmpObjClass = obj. getClass (); if (tmpObjClass. isArray () {// [I, [F basic type name length is 2 if (tmpObjClass. getName (). length ()> 2) {for (int I = 0, len = Array. getLength (obj); I <len; I ++) {Object tmp = Array. get (obj, I); if (tmp! = Null) {// The object toBeQueue. add (Array. get (obj, I) needs to be traversed in depth for non-basic types; }}} else {while (tmpObjClass! = Null) {Field [] fields = tmpObjClass. getDeclaredFields (); for (Field field: fields) {if (Modifier. isStatic (field. getModifiers () // static | field. getType (). isPrimitive () {// the basic type is continuous;} field. setAccessible (true); Object fieldValue = field. get (obj); if (fieldValue = null) {continue;} toBeQueue. add (fieldValue);} tmpObjClass = tmpObjClass. getSuperclass () ;}}return size;}/*** String. intern objects are excluded; computing objects are excluded, and endless loops are also avoided ** @ param visited * @ param obj * @ return */static boolean skipObject (SetVisited, Object obj) {if (obj instanceof String & obj = (String) obj ). intern () {return true;} return visited. contains (obj );}}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.