Java object memory analysis (analyzing the size and object structure of different objects in the JVM)

1. Internal structure of object memory in Java

      In the HotSpot virtual machine, the storage layout of objects in heap memory can be divided into three parts: object header, instance data and alignment padding, as follows.

  • Ordinary objects
    Insert image description here
  • array object
    Insert image description here

1.1. Object header

      The object header includes two parts, object tag and type pointer, the object header is similar to the request header of the http request, which stores key information of an object.

1.1.1. Object mark (Mark Word)

      Object tags mainly storelock information andGC tags , Java'ssynchronized lock is either a lock or a weight lock. There is a lock upgrade process (no lock state->biased lock->lightweight lock->weight lock),< /span> generational information, used to mark the age and survival status of objects for garbage collection. GCIt isGC mark stores the information needed for this process, and Lock information

1.1.2. Type pointer (Klass Point)

      Type pointer is easier to understand. It represents the address pointing to the class metadata of the object. The class metadata information of JDK1.8 is stored in the metaspace, so this Type pointer points to the address of the class information in the metaspace.

1.1.3. Array length (Length)

      If it is an array object, an array length value will also be stored in the object header.

1.2. Instance data

      Instance data stores other information in an object, such as a User class, which has a LongTypeidfield, then after this class instantiates the objectthe instance datais thisidFields can be easily understoodInstance data are member variables declared in a class.

1.3. Fill it

      Objects in Java are required to be an integer multiple of 8 bytes, because in the Java virtual machine, the memory layout of objects is arranged according to certain rules. This arrangement is called Object Alignment. .
      The purpose of object alignment is to allow the addresses of object member variables in memory to be naturally aligned, thereby improving the efficiency of CPU access to memory. When the object Header + Instance data will be performed when the occupied bytes are not equal to an integer multiple of 8Fill it , such as Object header + Instance data a> occupies 12 bytes, then will be filled with 4 bytes.

2. Pointer compression

      For the same object, if pointer compression is not enabled, the type pointer (Klass Point) occupies 8 bytes, and if pointer compression is enabled, it occupies 4 bytes. If pointer compression is not enabled, more memory will be occupied, and larger pointers will be used between main memory and cache. Moving data between places takes up a lot of bandwidth. Therefore, in order to reduce memory consumption and avoid excessive GC pressure on 64-bit platforms, the pointer compression function is enabled by default after JDK1.6.

type Enable pointer compression Turn off pointer compression
Object 16 16
int array 16 24
int 4 4
Integer 4 8
long 8 8
Long 4 8
String 4 8
  • Starting from JDK1.6 update14, in 64-bit operating systems, the JVM supports pointer compression and is enabled by default.
  • Enable pointer compression-XX:+UseCompressedOops (enabled by default), disable pointer compression:- XX:-UseCompressedOops

3. Code analysis object structure and memory size occupied

      I am using a 64-bit system, JDK1.8. To view the object structure and memory size, you need to introduce the jol-core package.

        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.10</version>
        </dependency>

2.1. Analyze Object object

    public static void main(String[] args) {
    
    
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
  • Pointer compression is enabled by default
    Insert image description here
    Here you can see that a Java Object empty object takes up 16 bytes, of which Mark Word and Klass Point take up 12 bytes in total, because they do not If a multiple of 8 is met, 4 bytes will be aligned and filled, which means that a minimum object will occupy 16 bytes.

  • Turn off pointer compression

    # 加上关闭指针压缩启动参数
    -XX:-UseCompressedOops
    

    Insert image description here
    After turning off pointer compression, the Klass Point occupies 8 bytes, and the Mark Word and Klass Point occupy a total of 16 bytes to satisfy multiples of 8 and do not require alignment padding.

2.2. Custom object analysis

  • Self-definedUserclass
public class User {
    
    
    private Long id;
    private Integer age;
    private String nickName;
}
  • PrintUserObject memory structure
    public static void main(String[] args) {
    
    
        User user = new User();
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }
  • Enable pointer compression
    Insert image description here

When pointer compression is turned onInstance data occupies a total of 24 bytes. The number of bytes occupied by basic types and packed types is Different, yes.

  • Turn off pointer compression
    Insert image description here
    After turning off pointer compressionInstance data occupies a total of 36 bytes, and also The 4 bytes of aligned padding occupy 16 bytes more memory than turning on pointer compression.

4. JVM heap memory should not exceed 32G

      Starting from JDK1.6 update14, in 64-bit operating systems, when the JVM heap memory is less than 32G, a memory object pointer compression technology will be enabled by default. In Java, all objects are allocated on the heap and then have a pointer referring to it. The size of the pointer to these objects is usually the size of the CPU word size, either 32bit or 64bit, depending on your processor, and the pointer points to the precise location of your value.
      For 32-bit systems, your memory can use up to 4G. For 64-bit systems more memory can be used. But 64-bit pointers mean greater waste, because your pointers themselves are larger. It's not just a waste of memory. What's worse is that larger pointers take up more bandwidth when moving data between main memory and caches (such as LLC, L1, etc.).
      Java uses a technology called memory pointer compression to solve this problem. Its pointer no longer represents the object's precise location in memory, but rather an offset. This means that a 32-bit pointer can reference 4 billion objects instead of 4 billion bytes. Eventually, that means the heap memory grows to 32G of physical memory, which can also be represented by a 32-bit pointer.
       Once you cross that magical 30-32G boundary, the pointers will switch back to the pointers of ordinary objects. The pointers of each object will become longer, and more CPU memory bandwidth will be used. Which means you actually lose more memory. In fact, when the memory reaches 40-50GB, the effective memory is equivalent to 32G memory when using memory object pointer compression technology.
       Even if there is enough memory, try not to exceed 32G, because it wastes memory, reduces CPU performance, and makes the GC cope with large memory.

Guess you like

Origin blog.csdn.net/weixin_44606481/article/details/134802419