Question 1. Please explain the creation process of the object?
- class loading
- class linking
- verification
- preparation
- resolution
- class initializing The process of static initialization
- Apply for object memory
- Assign default values to member variables
- Call the constructor <init>
- Assign initial values to member variables in order
- 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:
In-depth analysis of interview questions: Synchronized underlying implementation
Deadly Synchronized low-level implementation-heavyweight lock
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