Memory and Garbage Collection of JVM Part 2

3 Runtime area

3.1 Native method stack

insert image description here

3.2 Program Counter

insert image description here
The PC Register is the only area in the Java Virtual Machine Specification that does not specify any OutOfMemoryError.

Why is there a PC register?
Because the CPU will switch back and forth between different threads, after switching back, you need to know where to start executing.
The JVM bytecode interpreter needs to change the value in the PC register to clarify what bytecode instruction should be executed next.

Why should the PC register be set as thread private?
In order to accurately record the bytecode address being executed by each thread, the best solution is to allocate a PC register for each thread.

3.3 Method area

insert image description here
A memory space separate from the heap.

The size of the method area determines how many classes the system can save. If the system defines too many classes and the method area overflows, the virtual machine will also throw an OutOfMemoryError. For example, a large number of third-party jar packages are loaded; Tomcat deploys too many projects. A large number of generated reflection classes.

Store type information, constants, static variables, code cache compiled by the just-in-time compiler, etc.
[Type information]
(1) The complete effective name of this type (full qualified name = package name. Class name) (2) The complete effective name of the direct
parent class of this type (interface or java . (2) Domain related information includes: domain name, type, modifier (subset of public private protected static final volatile transient), etc. [Method information] (1) Method name, return type, number and type of parameters in order, method modifiers (2) Method bytecode, length of local variable table, static information of exception table.







[non-final class variables]
class variables are shared by all instances and can be accessed even when there is no instance.

pubic class MethodAreaTest {
    
    
	public static void main(String[] args) {
    
    
		Order order = null;
		// 不会有空指针异常
		order.hello();
		System.out.println(order.count);
	}
}

class Order {
    
    
	public static int count = 1;
	public static void hello() {
    
    
		System.out.println("hello");
	}
}

3.3.1 Evolution of the method area in Hotspot

Jdk7 used to be a permanent generation, and the memory in the JVM used
after JDK8 uses metaspace. The metaspace is not in the memory set by the virtual machine, but uses local memory .

3.3.2 Set the method area memory size

【java 7】
https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html
https://docs.oracle.com/cd/E74363_01/ohi_vbp_-_installation_guide–20160224-094432-html-chunked/s66.html
https://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html

-XX:PermSize Set the permanent generation initial allocation space. The default value is 20.75M. (Song Hongkang)

Option and default value Description
-XX:MaxPermSize=64m Size of the Permanent Generation. [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1-client: 32m.]. 64-bit machines default to 82M (Song Hongkang)
【java 8】
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

XX:MetaspaceSize=size
Sets the size of the allocated class metadata space that will trigger a garbage collection the first time it is exceeded. This threshold for a garbage collection is increased or decreased depending on the amount of metadata used. The default size depends on the platform.
windows下默认值是21M

-XX:MaxMetaspaceSize=size
is not limited by default. -1. set case-XX:MaxMetaspaceSize=256m

3.3.3 Runtime constant pool

https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

The constant pool table will be included in the bytecode file. The constant pool table contains various literals, symbolic references to types, fields, and methods.
The runtime constant pool is part of the method area. The constant pool is placed in the runtime constant pool after the class is loaded. The runtime constant pool is dynamic.

3.3.4 Example of using the method area

https://www.bilibili.com/video/BV1PJ411n7xZ?p=96&spm_id_from=pageDriver&vd_source=f4dcb991bbc4da0932ef216329aefb60

3.3.5 Evolution of the method area

Changes in the method area in HotSpot:

Before Jdk 1.6 There is a permanent generation (permanent generation), and static variables are stored on the permanent generation
jdk 1.7 There is a permanent generation, but it has been gradually "removed from the permanent generation". The string constant pool and static variables are removed from the permanent generation and stored in the heap
jdk 1.8 No permanent generation, type information, fields, methods, and constants are stored in metaspace (metaspace is in local memory), but string constant pools and static variables are still stored in the heap

[Reasons for permanent generation being replaced by metaspace]
(1) It is difficult to determine the space size of permanent generation.
In projects such as Web engineering, there are many dynamically loaded classes, which are prone to OOM of the permanent generation. The metaspace is not in the virtual machine, it uses local memory, and the size of the metaspace is only limited by the local memory.
(2) It is difficult to optimize the permanent generation.
Method area garbage collection mainly recycles two parts: obsolete constants in the constant pool and types that are no longer used.
How to determine that a class is no longer used is more difficult.

[The reason why the String Table is placed on the heap]
The permanent generation collection efficiency is very low, and it will only be triggered during the full gc. However, a large number of strings will be created during the development process, and the low recovery efficiency will lead to insufficient memory in the permanent generation.

[Where does the static variable exist]
The object entity referenced statically is always in the heap space. The object instance created by new must be in the heap space.
The HotSport virtual machine of JDK 7 and later versions chooses to store static variables and mapped Class objects in the Java language section together, and store them in the Java heap.

3.3.5 Garbage collection in the method area

There is no requirement in the "Java Virtual Machine Specification" to GC the method area.
ZGC does not support class unloading

3.4 stack

The stack runs, and the stack stores.

Thread private. The life cycle is consistent with the thread.

The 8 basic types of variables + reference variables of objects + instance methods are all allocated in the stack memory of the function.

A stack frame corresponds to a Java method.

The stack is a fast and efficient storage method, and its access speed is second only to the program counter. There is no GC or OOM problem in the stack.
insert image description here
insert image description here
The Java virtual machine specification allows the size of the Java stack to be dynamic or fixed .
If a fixed-size virtual machine stack is used, the stack capacity of each thread can be independently selected when the thread is created. If the stack capacity requested by the thread exceeds the maximum capacity allowed by the virtual machine stack, the Java virtual machine throws a StackOverFlowError.
If the Java virtual machine stack can be dynamically expanded, and cannot apply for enough memory when trying to expand, or there is not enough memory to create the corresponding virtual machine stack when creating a new thread, then the Java virtual machine throws OutOfMemoryError.

Use to -Xssset the maximum stack space for threads.
insert image description here
The stack frames contained in different threads are not allowed to have mutual references, that is, it is impossible to apply the stack frame of another thread in a stack frame.
If the current method calls other methods, when the method returns, the current stack frame will return the execution result of this method to the previous stack frame, and then, the virtual machine discards the current stack frame, making the previous stack frame the current stack frame.
There are two ways to return a Java function: one is a normal function return, such as using the return instruction; the other is to throw an exception (here is a real exception thrown. If the exception is caught and processed, it is a normal function return. ). Either way, the stack frame will be popped.

[Internal structure of the stack frame]
1 Local variable table, Local Variables
Local variable table is also called local variable array or local variable table.

Defined as a numeric array, mainly used to store method parameters and local variables defined in the method body (including basic data types, reference types and returnAddress types, etc.).

The local variable table is thread-private, so there is no data security problem.

The required capacity of the local variable table is determined at compile time and stored in the maximum local variables data item of the Code attribute of the method. The size of the local variable table is not changed during the execution of the method.

For a function, the more parameters and local variables it has, making the local variable table expand, the larger its stack frame will be.

The variables in the local variable table are only valid in the current method call. When the method is executed, the virtual machine completes the transfer process of the parameter value to the parameter variable list by using the local variable table. When the method call ends, as the method stack frame is destroyed, the local variable table will also be destroyed.

The most basic storage unit of the local variable table is Slot (variable slot). In the local variable table, types within 32 bits only occupy one slot (including the returnAddress type), and 64-bit types (long and double) need to occupy two slots. byte, short, and char will be converted to int before storage; boolean type will also be converted to int, 0 means false, non-zero means true.

If you need to access a 64-bit local variable (long or double) value in the local variable table, you only need to use the previous index (64-bit takes up two slots).

If the current frame is created by a construction method or an instance method, the this reference of the object will be placed at the slot with index 0, and the rest of the parameters will continue to be arranged in the order of the parameter list.

Slots can be reused.

public void test4() {
    
    
	int a = 0;
	{
    
    
		int b = 0;
		b = a + 1;
	}
	// 局部变量表的长度就是3
	// 变量c使用之前已经销毁的变量b的slot
	int c = a + 1;
}

index  Name
2     b 
0     this
1     a
2     c

[Comparison between static variables and local variables]
Classification of variables
According to data types: ① Basic data types ② Reference data types
According to the position declared in the class: ① Member variables: have undergone the default initialization process before use
<1> Class variables: In the prepare phase of linking, assign default initial values ​​​​to class variables; in the initial phase: execute statements in static code blocks and assign values.
<2> Instance variable: With the creation of the object, the instance variable space will be allocated in the heap space and assigned by default.
② Local variables: must be explicitly assigned before use. Otherwise, the compilation fails.

public void test5Temp() {
    
    
	int num;
	// 直接编译报错:Variable 'num' might not have been initialized.
	System.out.println(num);
}

In the stack frame, the part most closely related to performance tuning is the local variable table. When the method is executed, the virtual machine uses the local variable table to complete the transfer of the method.
The variables in the local variable table are the root nodes of important garbage collection, as long as the objects directly or indirectly referenced in the local variable table will not be recycled.

2 Operand stack, Operand stack, or expression stack

The operand stack, during method execution, writes data to or extracts data from the stack according to bytecode instructions.
For example

[8]                                                                        [23]
[15]           -----------add 操作执行之后--------->                         [其他元素]
[其他元素]

If the called method has a return value, its return value will be pushed into the operand stack of the current stack frame, and the offset address of the next instruction to be executed in the pc register will be updated.
The data types of the elements in the operand stack must exactly match the sequence of bytecode instructions. This is verified by the compiler during compilation, and again during the data flow analysis phase of the class verification phase of the class loading process.
The interpreter of the Java virtual machine is a stack-based execution engine, where the stack is the operand stack.

The operand stack is mainly used to save the intermediate results of the calculation process, and at the same time as a temporary storage space for variables during the calculation process. The operand stack is a working area of ​​the execution engine. When a method starts executing, a new stack frame is created, and the operand stack is also empty . The depth of the operand stack must be determined during compilation and stored in the max_stack of the Code attribute. The 32-bit type occupies one stack depth, and the 64-bit type occupies two. The operand stack cannot be accessed through array indexing, and data access can only be completed through stack push and pop operations.

[Stack top cache technology]
The zero-address instructions used by the virtual machine based on the stack architecture are more compact, but when an operation is completed, more push and pop instructions must be used, which means that more instruction dispatch and memory read and write times will be required.

Since operands are stored in memory, frequent memory reads and writes will inevitably affect execution speed. In order to solve this problem, the designers of HotSpot JVM proposed Top-of-Stack Cashing (ToS, Top-of-Stack Cashing) technology, which caches all the top elements of the stack in the registers of the physical CPU, thereby reducing the number of reads and writes to the memory and improving the execution efficiency of the execution engine.

3 Dynamic linking, Dynamic linking, or method reference to the runtime constant pool
Each stack frame contains a reference to the method in the runtime constant pool to which the frame belongs. The purpose of including this application is to support the current method to achieve dynamic linking. For example: invokedynamic instruction

When a Java source file is compiled into a bytecode file, all variable and method references are stored as symbolic references (Symbolic Reference) in the constant pool of the class file. For example: when describing that a method calls another method, it is represented by a symbolic reference pointing to the method in the constant pool, then the role of dynamic linking is to convert these symbolic references into direct references to the calling method.

Why do you need a constant pool?
The role of the constant pool is to provide some symbols and constants to facilitate instruction identification.

[Method call]
Static link: When a bytecode file is loaded into the JVM, if the called target method is known at compile time, and remains unchanged at runtime. In this case, the process of converting the symbolic reference of the calling method into a direct reference is called static linking.
Dynamic linking: If the called method cannot be determined at compile time, in other words, the symbolic reference of the calling method can only be converted into a direct reference at the runtime of the program. This kind of reference conversion process is dynamic, so it is also called dynamic linking.

Binding: Binding is a process in which a field, method, or class is replaced by a direct reference in a symbolic reference, and this process occurs only once.
Early binding: static linking, the target method is known at compile time and remains unchanged during runtime, and can be directly statically linked.
Late Binding: Dynamic Linking.

The process-oriented C language has only early binding. An object-oriented language with polymorphism and two binding methods: early binding and late binding.

Non-virtual method: The calling version is determined at compile time, and it is immutable at runtime. This is called a non-virtual method.
A non-virtual method is a virtual method.

Ordinary call instruction
invokestatic: calls a static method, and the only method version is determined in the parsing stage.
invokespecial: Invoke methods, private and parent methods, and the only method version is determined in the parsing phase.
invokevirtual: calls all virtual methods, and also calls final modified methods, but final modified methods are not virtual methods
invokeinterface: calls interface methods.
Dynamic call instruction
invokedynamic: dynamically parse out the method that needs to be called, and then execute it.

The first four instructions are solidified inside the virtual machine, and the method call execution cannot be human-intervened at all. The invokedynamic instruction is supported for determining the method version.

Statically typed language: the type is checked at compile time. Determine the type information of the variable itself.
Dynamically typed languages: Type checking occurs at runtime. Determine the type information of the variable value, and the variable has no type information.

[Essence of method overriding in Java language]
(1) Find the actual type of the object executed by the first element at the top of the operand stack, denoted as C (2)
If a method that matches the description in the constant and the simple name is found in type C, then check the access authority, if it passes, return the direct reference of this method, and the search process ends; If no suitable method is found java.lang.IllegalAccessError
,
throwjava.lang.AbstractMethodError

java.lang.IllegalAccessErrorDescription: The program tries to access or modify a property, or the program tries to call a method, but the program does not have access to this property or method. Generally, this situation will cause a compiler exception. If this error occurs at runtime, an incompatible change has occurred to a class.

In order to improve performance, the JVM creates a virtual method table (virtual method table) in the method area of ​​the class. Use indexed tables instead of lookups. Each class has a virtual method table, which stores the actual entry of each method. The virtual method table will be created and initialized during the linking phase (Resolving phase) of the class loading process. After the initial value of the variable of the class is prepared, the JVM will also initialize the method table of the class.

4 The return address of the method, Return Address, or the definition of normal and abnormal exit of the method
Store the value of the PC register calling the method

Normal exit saves the value of the PC register, and abnormal exit does not save it. The return address of abnormal exit should be determined according to the exception table , and this part of information will not be saved in the stack frame.

ireturn: the return value is boolean, byte, char, short or int
lreturn: long
freturn: float
dreturn: double
areturn: reference type
return: no return value, void method, construction method, static code block, etc.

5 Additional information
For example, information that provides support for program debugging.

3.4.1 Several interview questions

[Stack overflow]
StackOverFlowError

insert image description here

3.5 heaps

The Java virtual machine specification stipulates that the heap can be in a physically discontinuous memory space, but it should be logically continuous .

The thread private buffer (Thread Local Allocation Buffer, TLAB) can be specially divided in the heap space.

insert image description here
Java 8 and later are logically divided into three parts: new generation + old generation + metaspace (method area).
insert image description here
insert image description here

-Xms: the starting size of the heap (young generation + old generation), ms is the memory start
-Xmx: the maximum size of the heap
By default, the initial heap size is physical memory / 64; the maximum memory is physical memory / 4;

View the set parameters:
Method 1: jps / jstat -gc process id
Method 2: -XX:+PrintGcDetails

When Eden is full, YGC (also known as MinorGC) will be triggered, and objects in the Eden area and the Survivor area will be recycled.

The operating rules of the survivor area s0 and s1 area: there is an exchange after copying, and the empty one is the to area.
insert image description here

Garbage collection: frequently collected in the young area, rarely collected in the old area, and almost never collected in the permanent generation/meta space.

3.5.1 Minor GC, Major GC and Full GC

GC is divided into partial collection (Partical GC) and overall collection (Full GC) according to the recovery area.
Part of the collection is divided into: (1) New generation collection: Minor GC / Young GC, just the garbage collection of the new generation. Trigger condition: when the Eden area is full. Minor GC will cause STW, suspend the threads of other users, and wait for the garbage collection to end before the user threads will resume running. (2) Old generation collection: Major GC / Old GC, just garbage collection in the old generation. Currently, only the CMS GC has the behavior of separately collecting the old generation. Note that in many cases, Major GC and Full GC are used in confusion, and it is necessary to specifically distinguish whether it is old generation recycling or overall recycling. Trigger condition: When there is insufficient space in the old generation, it will try to trigger minor gc first. If there is still insufficient space after minor gc, major gc will be triggered. (3) Mixed collection: Mixed GC, which collects the entire new generation and part of the old generation. Currently, only the G1 GC exhibits this behavior.

Whole heap collection: Full GC, collects the entire Java heap and method area.
The execution of Full GC is as follows: (1) When calling System.gc(), the system recommends to execute Full GC, but it is not necessarily executed. (2) There is not enough space in the old generation. (3) There is not enough space in the method area. (4) After Minor GC, the average size of the old generation is larger than the available memory of the old generation. (5) When copying to the to area, if the object size is larger than the available memory in the to area, the object is transferred to the old generation, and the available memory in the old generation is smaller than the object size.

3.5.2 Reasons for using generational thinking

No generation is also possible, the only reason for generation is GC performance optimization .

3.5.3 Memory allocation strategy

  • Priority allocation to Eden
  • Large objects are allocated directly to the old generation.
    The program should try to avoid too many large objects.
  • Long-lived objects are allocated to the old generation.
  • Dynamic object age judgment
    If the sum of the size of all objects of the same age in the Survivor area is greater than half of the Survivor space, objects whose age is greater than or equal to the new age can directly enter the old age without waiting for the age required in MaxTenuringTreshold.
  • Space Allocation Guarantee
    -XX:HandlePromotionFailure

3.5.4 TLAB

Divide the Eden area and allocate a private cache area for each thread.
The JVM uses TLAB as the first choice for memory allocation.
By default, the TLAB space is very small, only 1% of the Eden space.

3.5.5 Is the heap the only option for allocating object storage

【Allocation on the stack】

If after escape analysis, it is found that an object does not escape the method, then it can be optimized to be allocated on the stack.

[Synchronization omitted]

Escape analysis will perform lock elimination optimization.

public void f() {
    
    
	Object hollis = new Object();
	synchronized (hollis) {
    
    
		System.out.println(hollis);
	}
}

=====优化后=======
public void f() {
    
    
	Object hollis = new Object();
	System.out.println(hollis);
}

【Scalar replacement】

A scalar is data that cannot be broken down into smaller data. The primitive data types in Java are scalars. In contrast, data that can be decomposed is called aggregation. Objects in Java are aggregates.
In the JIT stage, if escape analysis finds that an object will not be accessed by the outside world, then after JIT optimization, the object will be disassembled into several scalars for replacement. This is scalar substitution.

[Metadata area]
Escape analysis is not mature. Escape analysis itself requires huge performance consumption, and there is no guarantee that escape analysis will bring benefits.

The intern string cache and static variables are not allocated in the metadata area, but allocated directly on the heap.

Therefore, objects are basically allocated on the heap.

3.5.5 Heap Tuning

insert image description here
insert image description here
insert image description here
insert image description here

4 Object instantiation, memory layout and access positioning

4.1 Object instantiation

4.1.1 How objects are created

  • new
    variant 1: static method of XXX, such as getInstance of singleton mode
    variant 2: static method of xxxBuilder/xxxFactory
  • Reflection
    Class.newInstance: Only constructors with empty parameters can be called, and the permissions must also be public
    Constructor.newInstance: Constructors with no parameters or parameters can be called, and permissions are not required.
  • To use clone,
    you need to implement the clone method
  • use deserialization
  • Three-party library Objenesis

4.1.2 Steps of Object Creation

[1 Determine whether the corresponding class is loaded, connected and initialized]
[2 Allocate memory for the object]
If the memory is regular, use pointer collision.
If the memory is irregular, allocate memory through the free list.
[3 Dealing with concurrency security issues]
CAS failure retry, area locking, etc. are used to ensure the atomicity of updates.
TLAB
[4 Initialize the allocated space]
Set default values ​​for all attributes to ensure that the object instance can be used directly when no value is assigned
[5 Set the object header of the object]

[6 Explicit initialization]
init and clinit

4.2 Memory layout of objects

[object head]

  • Runtime metadata (Mark Word)
    hash code
    GC generational age
    Lock status flag
    Lock held
    by thread Bias thread id
    bias time stamp
  • Type pointer
    points to the Class object

If it is an array, the length of the array will also be recorded.
[Instance data]
The variable defined in the parent class is before the variable of the subclass.
Fields of the same width are always allocated together.
If the CompactFields parameter is true (default is true): the narrow variable of the subclass may be inserted into the gap of the parent class variable.
【Alignment filling】

4.3 Object access location

  • Handle access
    Benefits: When the object is moved, you only need to modify the pointer of the handle.
    Disadvantages: It needs to open up memory for the handle pool, two-level reference, and the access efficiency is relatively low.
  • Direct pointers
    HotSpot uses direct pointers.
    Advantages:
    Disadvantages:

5 direct memory

IO NIO (New IO / Non-Blocking IO)
byte[] / char[] Buffer
Stream Channel
// 直接分配本地内存空间
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 1024 * 1024)

Direct memory is neither part of the runtime data area nor a memory area as defined in the Java Virtual Machine Specification. It is outside the Java heap and directly applies to the system for memory space.
Originated from NIO, native memory is manipulated through DirectByteBuffer stored in the heap.
Generally, the speed of accessing direct memory is better than that of Java heap, and the read and write performance is high.
In the case of OOM,
you can MaxDirectMemorySizeset the size of the direct memory, which is consistent with the parameter value of -Xmx by default.

6 Execution Engine

6.1 Reasons for the coexistence of interpreter and JIT compiler

JIT: Fast
Interpreter: After the program starts, the interpreter can take effect immediately, saving compilation time and executing it immediately.

[Method Call Counter]
Statistics method call times. The default threshold is 1500 times in Client mode and 10000 times in Server mode. Thresholds can be -XX:CompileThresholdset via .

The counter counts the relative execution frequency (the number of times a method is called over a period of time). When a certain time limit is exceeded and the number of method calls still does not reach the threshold, the count will be halved. This process is called Counter Decay. This period of time is called the half-life period (Counter Half life time).

-XX:-UseCounterDecay: Turn off heat decay
-XX:-CounterHalfLifeTime: Half-life period, unit s.
[End counter]
Counts the number of code executions in the loop body.
Instructions that jump backward when encountering control flow in the bytecode are called "Back Edge".

-Xint: fully use the interpreter to execute
-Xcomp: completely use the just-in-time compiler to execute the program. If there is a problem with the just-in-time compiler, the interpreter will step in to execute.
-Xmixed: Use the mixed mode of interpreter + just-in-time compiler to execute together.

There are two JIT compilers in HotSpot VM, namely Client Compiler and Server Compiler. Referred to as C1 and C2 compilers.
-client: C1 compiler. The C1 compiler performs simple and reliable optimization of bytecode in a fraction of the time. Has faster compilation speed.
Method inlining: compile the referenced function code to the reference point, reduce the generation of stack frames, and reduce the parameter passing and jumping process.
Devirtualization: Inlining the only implementing class.
Honor Elimination: Fold some code that will not be executed during runtime.
-server: C2 compiler. The C2 compiler performs longer aggressive optimizations. Optimized code is more efficient.
Scalar replacement
Stack allocation
Synchronization elimination.

Layered compilation strategy: C1 compilation can be triggered when the program is interpreted and executed, and simple optimization is performed when compiling bytecode into machine code. If performance monitoring is added, the C2 compiler will perform aggressive optimization based on the performance monitoring information.
After java7, as long as it is in -server mode, the hierarchical compilation strategy will be enabled by default.

6.2 AOT Compiler

Static ahead of time compiler, Ahead of Time Compiler. An AOT compiler converts bytecode into machine code before the program runs.

7 StringTable

The data structure of String in java8 is char[], and changed to byte[] in jdk 9. Changed
motivation: According to statistics, most of the strings are Latin letters, and it is a waste of space to use char array storage.
The string encoding flag (encoding-flag) has been added to Java 9's String.

Strings with the same content will not be stored in the string constant pool.

String Pool is a fixed-size HashTable with a default length of 1009 (the default value in jdk 6). In jdk 7, the default length of StringTable is 60013 (the length can be set, but there is no requirement). Starting from JDK 8, 1009 is the minimum value that can be set.

7.1 String concatenation operation

  1. Constants and constant splicing results are in the constant pool, the principle is compile-time optimization.
public void test1() {
    
    
	String s1 = "a" + "b" + "c";
	String s2 = "abc";

	System.out.println(s1 == s2); // true
	System.out.println(s1.equals("s2")); // true 
}
  1. Constants with the same content will not exist in the constant pool
  2. As long as one is a variable, the result is on the heap. The principle of variable splicing is StringBuilder
public void test2() {
    
    
	String s1 = "javaEE";
	String s2 = "hadoop";
	String s3 = "javaEEhadoop";
	String s4 = "javaEE" + "hadoop";
	String s5 = s1 + "hadoop";
	String s6 = "javaEE" + s2;
	/**
	* 执行细节:
	* ① builder = new StringBuilder();
	* ② builder.append(s1)
	* ③ builder.append(s2)
	* ④ builder.toString(); 约等于new String
	*  
	* jdk 5.0和之后使用的是StringBuilder,5.0之前使用的StringBuffer
	**/
	String s7 = s1 + s2;

	System.out.println(s3 == s4); // true
	System.out.println(s3 == s5); // false
	System.out.println(s3 == s6); // false
	System.out.println(s3 == s7); // false
	System.out.println(s5 == s6); // false	
	System.out.println(s5 == s7); // false
	System.out.println(s6 == s7); // false	
	
	String s8 = s6.intern();
	System.out.println(s3 == s8); // true
}
public void test4() {
    
    
	final String s1 = "a";
	final String s2 = "b";
	String s3 = "ab";
	String s4 = s1 + s2; // 因为有final修饰,这里是“常量”
	System.out.println(s3 == s4); // true
}
  1. If the splicing result calls the intern method, it will actively put the string that is not in the constant pool into the pool, and return the address of this object.

7.2 intern method

【How many objects will new String("ab") create?
Two, the new one, the "ab" in the string constant pool is the other.

Use jclasslib to view the compiled bytecode file to know.

[String str = new String("a") + new String("b") How many objects will be created?
Object 1: new StringBuilder
object 2: new String("a")
object 3: "a" object in the constant pool
4: new String("b")
object 5: "b" object in the constant pool
6: toString() in StringBuilder will create new String("ab"), but there is no "ab" in the string constant pool

        // new 出来的对象
        String s = new String("1");
        // 没有作用,常量池中已经有“1”了。
        s.intern();
        // 指向常量池中的string
        String s2 = "1";
        // jdk 6/7/8以及之后,都是false
        System.out.println(s == s2);

        // s3 变量的地址就是new String("11")
        String s3 = new String("1") + new String("1");
        // "11"加入到了常量池中
        // jdk 6: 创建了一个新的对象“11”,放到常量池中
        // jdk 7/8和以后:常量池中记录了堆里面的“11”的地址,没有创建新的。
        s3.intern();
        // s4就是常量池中“11”的地址
        String s4 = "11";
        System.out.println(s3 == s4);
		// s3 变量的地址就是new String("11")
        String s3 = new String("1") + new String("1");
        // 字符串常量池中创建新的。 
        String s4 = "11";
        String s5 = s3.intern();
        System.out.println(s3 == s4); // false
        System.out.println(s5 == s4); // true
 		// s = new String("ab")
        String s = new String("a") + new String("b");
        // jdk 6 : s2 != s
        // jdk 17 : s2 == s.
        String s2 = s.intern();
        System.out.println(s2 == "ab"); // jdk 6: true.    jdk 17: true
        System.out.println(s == "ab");  // jdk 6: false.   jdk 17: true
        String x = "ab";
        // s = new String("ab")
        String s = new String("a") + new String("b");
        String s2 = s.intern();
        System.out.println(s2 == "ab"); // true
        System.out.println(s == "ab"); // false
        String s1 = new String("a") + new String("b");
        // 常量池中的字串引用指向s1
        s1.intern();
        // 常量池中的字串
        String s2 = "ab";
        System.out.println(s1 == s2); // open jdk 17:true
        // s1是new出来的
        String s1 = new String("ab");
        // 没有作用,常量池中已经有ab了。
        s1.intern();
        String s2 = "ab";
        System.out.println(s1 == s2); // open jdk 17:false

7.3 String deduplication operation of G1

It is not enabled by default.
Deduplicate the String on the heap.

Guess you like

Origin blog.csdn.net/kaikai_sk/article/details/131744449