[In-depth understanding of JVM] 4. First-line Internet interview questions + object creation process + what does the object header specifically include + object positioning? [Required for Interview]

 Previous post: [In-depth understanding of JVM] 3. CPU storage + MESI + CPU pseudo-sharing + CPU disorder problem and code demonstration [interview essential]

 

Question 1. Please explain the creation process of the object?

  1. class loading
  2. class linking
    1. verification
    2. preparation
    3. resolution
  3. class initializing The process of static initialization
  4. Apply for object memory
  5. Assign default values ​​to member variables
  6. Call the constructor <init>
    1. Assign initial values ​​to member variables in order
    2. Execute the construction method statement: first call super

Question 2. The storage layout of the object in memory?

1. Let me talk about the command to observe the configuration of the virtual machine:

java -XX:+PrintCommandLineFlags -version

Idea settings:

The effect of executing the command on the virtual machine:

C:\Users\zhouwei>java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=266984512 Initial heap size
-XX:MaxHeapSize=4271752192 Maximum heap size
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers: (compressed by default
Yes , change the + sign to-and it will no longer be compressed)  -XX:+UseCompressedOops(oops): ordinary object pointers ordinary object pointers such as the referenced string see below
-XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8 .0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

 2. Ordinary objects

Note: Some places are Klass Pointer and some are

A Java object in memory is divided into three parts: object header, instance data, and alignment .

  • Object header : mark 8Bytes is used to mark lock information, GC information, IdentityHashCode, etc.
  • class Pointer Class pointer : jvm enables memory compression (-XX:+UseCompressedClassPointer), 4 bytes. Do not open, 8 bytes. It is enabled by default and is used to mark the instance of which class the object is. For example: Object.class.
  • Instance data (instance data): including all member variables of the object, the size is determined by each member variable, if there is no member variable, this block is empty, the basic type (int, float 4 bytes long, double 8 bytes, char, Short 2 bytes, byte 1 byte, boolean (the actual size of 1bit occupies 1 byte).
    • Reference type: -XX:+UseCompressedOops is 4 bytes and is not turned on to 8 bytes, Oops Ordinary Object Pointers
  •  Padding alignment : a multiple of 8 (because it is not a direct read when reading, it is a read block, usually a multiple of 8 bytes, so the efficiency will be higher)

 3. Array object

  • Object header : mark 8Bytes is used to mark lock information, GC information, IdentityHashCode, etc.
  • class Pointer Class pointer : jvm enables memory compression (-XX:+UseCompressedClassPointer), 4 bytes. Do not open, 8 bytes. It is enabled by default, which is used to mark the instance of which class the object is. For example: Object.class
  • Array length : how many elements are in the 4-byte marker array
  • Array data (instance data) : According to the array type m and length n, the length is m*n.
          If the element is a basic type, such as byte/boolean/short/char/int/long/double, then m is the corresponding length;
          If the element is an array, m is a 4-byte reference
          If the length of the array is 0, this block is empty
  • Padding alignment : The number of bytes occupied by an object must be a multiple of 8, and padding alignment is used for insufficient

 Experiment: Use the mechanism of java agent (the agent between the class file and the memory, this agent has to be implemented by itself). The following is a supplement to the JOL tool, which is relatively simple.

1. Create a file ObjectSizeAgent (similar to an agent before the memory)

public class ObjectSizeAgent {
    // 类似调弦的作用
    private static Instrumentation inst;

    public static void premain(String agentArgs, Instrumentation _inst) {
        inst = _inst;
    }

    public static long sizeOf(Object o) {
        return inst.getObjectSize(o);
    }
}

2. Create META-INF/MANIFEST.MF in the src directory

Here you can just Premain-Class: com.mashibing.jvm.agent.ObjectSizeAgent

Manifest-Version: 1.0
Created-By: mashibing.com
Premain-Class: com.mashibing.jvm.agent.ObjectSizeAgent

3. Package the jar file

4. Introduce the Jar package in the project that needs to use the Agent Jar project structure-project settings-library Add the jar package

5. The class of the Agent Jar is needed at runtime, and the parameters are added:

Which jar file is used as a proxy to run my virtual machine:

-javaagent:C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar

6. How to use this class:

Measured object: 16 bytes object analysis:

The object header is 8 bytes, which should be 8 bytes (64-bit) because it is compressed when it is turned on by default, and it is compressed into 4 bytes (class_pointer).

All the entire object is 8+4=12 bytes, 16 bytes when measured, because there is a padding (alignment) 4 bytes behind.

8+4+padding

Array analysis:

Object header 8 bytes + class_pointer (many on the Internet write this as OOPS, which is wrong) Compress 4 bytes, length 4 bytes = 16 bytes.

-XX:+UseCompressedClassPointers changes the + sign to-without compression, and the array becomes 24 bytes.

Object header 8 bytes + class_pointer uncompressed 8 bytes + length 4 bytes + paddding 4 bytes = 24 bytes

Note: A: -XX:+UseCompressedOops(oops): ordinary object pointers such as the referenced String see below

           B: -XX:+UseCompressedClassPointers: (compressed by default, change the + sign to-to no longer compress) 

public class T03_SizeOfAnObject {
    public static void main(String[] args) {
         // ObjectSizeAgent这个jar包是自己生成的。
        System.out.println(ObjectSizeAgent.sizeOf(new Object()));
        System.out.println(ObjectSizeAgent.sizeOf(new int[] {}));
        System.out.println(ObjectSizeAgent.sizeOf(new P()));
    }

    // 一个Object占多少个字节
    // -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
    // Oops = ordinary object pointers
    private static class P {
                        //8 _markword
                        //4 _class pointer
        int id;         //4
        String name;    //4
        int age;        //4

        byte b1;        //1
        byte b2;        //1

        Object o;       //4
        byte b3;        //1

    }
}

 Hotspot open memory compression rules (64-bit machine)

1. Below 4G, directly cut the high 32-bit 2. 4G-32G, the memory compression ClassPointers Oops is turned on by default 3. 32G, the compression is invalid, and the use of 64-bit memory is not the bigger the better (^-^)

3. What does the object header include?

1.8 implementation, C++ file, go to see the Hotspot source code. (Very complicated)

Just know the time (just listen to it):

For details about the lock status, please refer to this article: [Java Object Analysis] Object headers that have to be understood

The Object Header of the HotSpot virtual machine includes two parts of information. The first part is used to store the runtime data of the object itself , such as HashCode, GC generation age, lock status flags, locks held by threads, Partial thread ID, biased timestamp, etc. The length of this part of the data is 32 and 64 Bits respectively in the 32-bit and 64-bit virtual machines (not considering the scenario where the compressed pointer is turned on). The official name is "Mark Word".

Objects need to store a lot of runtime data, which actually exceeds the limit that the 32- and 64-bit Bitmap structure can record. However, the object header information is an additional storage cost that has nothing to do with the data defined by the object itself. Taking into account the space efficiency of the virtual machine, Mark Word is designed as a non-fixed data structure to store as much information as possible in a very small space. It reuses its own storage space according to the state of the object. For example, when the object in the 32-bit HotSpot virtual machine is not locked, 25Bits in the 32 Bits space of Mark Word is used to store the object hash code (HashCode), 4Bits is used to store the object generation age, and 2Bits is used The storage lock flag bit, 1Bit is fixed to 0, and the storage contents of the object in other states (lightweight lock, heavyweight lock, GC mark, biasable) are shown in the following table.  

 

The other part of the object header is the type pointer , which is a pointer to the metadata of the object's class. The virtual machine uses this pointer to determine which class instance the object is . Not all virtual machine implementations must keep type pointers on the object data. In other words, finding the metadata information of the object does not necessarily go through the object itself . 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 ordinary Java object, but from the metadata of the array Unable to determine the size of the array in.  

The lock flag corresponds to a unique lock state with whether the bias lock corresponds to

There are a total of four lock states : unlocked state, biased lock, lightweight lock and heavyweight lock.

Biased lock : (Enable parameter -XX: +UseBiasedLocking, which is the default value of JDK 1.6) In order to make the thread to obtain the lock on behalf of the drive lower and introduce biased lock, then, "locks are always held by the same thread, rarely "Competition occurs", which means that the lock is always owned by the thread that occupies him first, and this thread is the biased thread of the lock. Then you only need to record the biased thread ID when the lock is first owned. In this way, the biased thread keeps holding the lock and releases the lock until the contention occurs. After each synchronization, check whether the lock's biased thread ID is consistent with the current thread ID. If they are consistent, enter the synchronization directly, and exit the synchronization. There is no need to go to the CAS to update the object header every time the lock is unlocked. It is not always biased towards the same thread. At this time, the lock needs to be expanded to a lightweight lock to ensure fair competition between threads. Optimistic lock.

Lightweight lock : The kernel has not been involved. The process of acquiring a lightweight lock is different from a biased lock. The threads competing for the lock first need to copy the Mark Word in the object header to the lock record of the frame stack. After the copy is successful, use the CAS operation to try to update the Mark Word of the object to a pointer to the current thread. If this update action is successful, then this thread owns the lock of the object. If the update fails, it means that there are multiple threads competing.

  • Lightweight locks need to release the lock every time they exit the synchronization block, while the bias lock releases the lock when contention occurs.
  • Every time you enter and exit the synchronization block, CAS needs to update the object header
  • When the contention for the lightweight lock fails, spin attempts to preempt the lock

Heavyweight lock : There is a kernel involved. The resource consumption is relatively high. The locking and unlocking process of a heavyweight lock is similar to that of a lightweight lock. The difference is: after the competition fails, the thread is blocked. After the lock is released, the blocked thread is awakened. The spin lock is not used, so it will not consume the CPU so much. The lock is suitable for use in the case of a long execution time of the synchronized block. With the competition of locks, locks can be upgraded from biased locks to lightweight locks, and then upgraded heavyweight locks (but the upgrade of the lock is one-way, that is to say, it can only be upgraded from low to high, and there will be no locks. Downgrade). In JDK 1.6, biased locks and lightweight locks are turned on by default. We can also disable biased locks through -XX:-UseBiasedLocking.

The hashCode of the object is usually not in 25bit, and it will be marked only when it is called.

Hashcode is also quite special: (didn't understand)

  • The hashcode method of the object is rewritten: the hashcode calculated according to the original content, the result calculated by the rewritten hashcode method does not exist here.
  • The hashcode of the object has not been overwritten: then the default is to call the hashcode generated by os:random, which can be obtained through System.identityHashCode; the rule for generating hashcode by os:random is: next——rand=(16807seed)mod(2*31-1 ), so you can use 31-bit storage. Once the hashcode is generated, the JVM will record it in the markword. Call it identityHashCode.

When will the hashcode be generated?

  • When calling the unrewritten hashcode method and system.identityHashCode.

There are two positions marked GC .

Why is the GC age set to 15 by default?

  • Because there are only 4 heads of generational age, the maximum is 15. (Some people say that this number can be adjusted, nonsense)

markword 64 bits 8 bytes

Only find 32-bit images

After an object has calculated the identityHashCode, it cannot enter the biased lock state?

Because the hashcode has been calculated, the first 25 bits are already occupied, so the bias lock state cannot be entered.

Interested can refer to:

If you die at the bottom of the Synchronized implementation, what are you afraid of during the interview?

In-depth analysis of interview questions: Synchronized underlying implementation

Deadly Synchronized low-level implementation-heavyweight lock

This article allows you to understand the underlying implementation of Synchronized and kill the interviewer in seconds

 

4. Object positioning

Refer to "In-depth understanding of JAVA virtual machine"

T t = new T(); How does t find the actual new object?

1. Handle pool:

  • Relatively low efficiency and stable
  • But in the GC (three-color mark algorithm) garbage collection, the efficiency will be higher.
  • The biggest advantage of using handle access is that a stable handle address is stored in the reference. After the object is moved (moving the object during garbage collection is a very common behavior), you only need to change the object instance address in the handle, and the reference does not need to be modified.

2. Direct pointer:

  • The access speed is fast, it reduces the time overhead of a pointer positioning. Since java is an object-oriented language, java objects are accessed very frequently during development. Therefore, the accumulation of such overhead is very considerable, and vice versa. speed.

 

 

Supplement: Use the JOL tool JOL tool and the size and distribution of the analysis object in the JVM to replace the previous java agent method.

The full name of JOL is Java Object Layout , which is a tool for analyzing the layout of objects in the JVM. This tool uses Unsafe and JVMTI to decode the layout, so the analysis results are more accurate. Generally, analyzing the size of java objects requires manual estimation of the approximate heap occupancy of the cached objects according to the size of the basic Java data types and the size of the content, but the trouble is not accurate. And OpenJDK provides a JOL package, which can help us calculate the size of an object at runtime, which is a very good tool.

Application: Analyze the size and distribution of objects in the JVM

Dependence :

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
</dependency>
/**
 * @author zhouwei
 * @date
 */

public class JolDemo {

    static Object generate() {
        Map<String, Object> map = new HashMap<>();
        map.put("a", new Integer(1));
        map.put("b", "b");
        map.put("c", new Date());

        for (int i = 0; i < 10; i++) {
            map.put(String.valueOf(i), String.valueOf(i));
        }
        return map;
    }

    static void print(String message) {
        System.out.println(message);
        System.out.println("-------------------------");
    }

    public static void main(String[] args) {
        Object obj = generate();

        // 查看对象内部信息
        print("查看对象内部信息:"+ClassLayout.parseInstance(obj).toPrintable());

        // 查看对象外部信息:包括引用的对象
        print("查看对象外部信息:包括引用的对象"+GraphLayout.parseInstance(obj).toPrintable());

        // 查看对象占用空间总大小
        print("查看对象占用空间总大小size : " + GraphLayout.parseInstance(obj).totalSize());
    }

}

 Print result:

查看对象内部信息:java.util.HashMap object internals:
 OFFSET  SIZE                       TYPE DESCRIPTION                               VALUE
      0     4                            (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                            (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                            (object header)                           a8 37 00 f8 (10101000 00110111 00000000 11111000) (-134203480)
     12     4              java.util.Set AbstractMap.keySet                        null
     16     4       java.util.Collection AbstractMap.values                        null
     20     4                        int HashMap.size                              13
     24     4                        int HashMap.modCount                          13
     28     4                        int HashMap.threshold                         24
     32     4                      float HashMap.loadFactor                        0.75
     36     4   java.util.HashMap.Node[] HashMap.table                             [null, (object), (object), (object), null, null, null, null, null, null, null, null, null, null, null, null, (object), (object), (object), (object), (object), (object), (object), (object), (object), (object), null, null, null, null, null, null]
     40     4              java.util.Set HashMap.entrySet                          null
     44     4                            (loss due to the next object alignment)
Instance size: 48 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

-------------------------
查看对象外部信息:包括引用的对象java.util.HashMap@10dba097d object externals:
          ADDRESS       SIZE TYPE                      PATH                           VALUE
        76b7302b0         48 java.util.HashMap                                        (object)
        76b7302e0         24 java.lang.String          .table[1].key                  (object)
        76b7302f8         24 [C                        .table[1].key.value            [a]
        76b730310       2112 (something else)          (somewhere else)               (something else)
        76b730b50         16 java.lang.Integer         .table[1].value                1
        76b730b60         80 (something else)          (somewhere else)               (something else)
        76b730bb0         32 java.util.HashMap$Node    .table[1]                      (object)
        76b730bd0         24 java.lang.String          .table[2].key                  (object)
        76b730be8         24 [C                        .table[2].key.value            [b]
        76b730c00         32 java.util.HashMap$Node    .table[2]                      (object)
        76b730c20         24 java.lang.String          .table[3].key                  (object)
        76b730c38         24 [C                        .table[3].key.value            [c]
        76b730c50      70760 (something else)          (somewhere else)               (something else)
        76b7420b8         24 java.util.Date            .table[3].value                (object)
        76b7420d0         32 java.util.HashMap$Node    .table[3]                      (object)
        76b7420f0         24 [C                        .table[16].key.value           [0]
        76b742108         24 java.lang.String          .table[16].key                 (object)
        76b742120         24 [C                        .table[16].value.value         [0]
        76b742138         24 java.lang.String          .table[16].value               (object)
        76b742150         32 java.util.HashMap$Node    .table[16]                     (object)
        76b742170         24 [C                        .table[17].key.value           [1]
        76b742188         24 java.lang.String          .table[17].key                 (object)
        76b7421a0         24 [C                        .table[17].value.value         [1]
        76b7421b8         24 java.lang.String          .table[17].value               (object)
        76b7421d0         32 java.util.HashMap$Node    .table[17]                     (object)
        76b7421f0         24 [C                        .table[18].key.value           [2]
        76b742208         24 java.lang.String          .table[18].key                 (object)
        76b742220         24 [C                        .table[18].value.value         [2]
        76b742238         24 java.lang.String          .table[18].value               (object)
        76b742250         32 java.util.HashMap$Node    .table[18]                     (object)
        76b742270         24 [C                        .table[19].key.value           [3]
        76b742288         24 java.lang.String          .table[19].key                 (object)
        76b7422a0         24 [C                        .table[19].value.value         [3]
        76b7422b8         24 java.lang.String          .table[19].value               (object)
        76b7422d0         32 java.util.HashMap$Node    .table[19]                     (object)
        76b7422f0         24 [C                        .table[20].key.value           [4]
        76b742308         24 java.lang.String          .table[20].key                 (object)
        76b742320         24 [C                        .table[20].value.value         [4]
        76b742338         24 java.lang.String          .table[20].value               (object)
        76b742350         32 java.util.HashMap$Node    .table[20]                     (object)
        76b742370         24 [C                        .table[21].key.value           [5]
        76b742388         24 java.lang.String          .table[21].key                 (object)
        76b7423a0         24 [C                        .table[21].value.value         [5]
        76b7423b8         24 java.lang.String          .table[21].value               (object)
        76b7423d0         32 java.util.HashMap$Node    .table[21]                     (object)
        76b7423f0         24 [C                        .table[22].key.value           [6]
        76b742408         24 java.lang.String          .table[22].key                 (object)
        76b742420         24 [C                        .table[22].value.value         [6]
        76b742438         24 java.lang.String          .table[22].value               (object)
        76b742450         32 java.util.HashMap$Node    .table[22]                     (object)
        76b742470         24 [C                        .table[23].key.value           [7]
        76b742488         24 java.lang.String          .table[23].key                 (object)
        76b7424a0         24 [C                        .table[23].value.value         [7]
        76b7424b8         24 java.lang.String          .table[23].value               (object)
        76b7424d0         32 java.util.HashMap$Node    .table[23]                     (object)
        76b7424f0         24 [C                        .table[24].key.value           [8]
        76b742508         24 java.lang.String          .table[24].key                 (object)
        76b742520         24 [C                        .table[24].value.value         [8]
        76b742538         24 java.lang.String          .table[24].value               (object)
        76b742550         32 java.util.HashMap$Node    .table[24]                     (object)
        76b742570         24 [C                        .table[25].key.value           [9]
        76b742588         24 java.lang.String          .table[25].key                 (object)
        76b7425a0         24 [C                        .table[25].value.value         [9]
        76b7425b8         24 java.lang.String          .table[25].value               (object)
        76b7425d0         32 java.util.HashMap$Node    .table[25]                     (object)
        76b7425f0        144 [Ljava.util.HashMap$Node; .table                         [null, (object), (object), (object), null, null, null, null, null, null, null, null, null, null, null, null, (object), (object), (object), (object), (object), (object), (object), (object), (object), (object), null, null, null, null, null, null]


-------------------------
查看对象占用空间总大小size : 1752

Next: [In-depth understanding of JVM] 5. Run-time data areas + common instructions [required for interviews]

Guess you like

Origin blog.csdn.net/zw764987243/article/details/109517914