JVM learning
This article is based on JVM [produced by dark horse programmer] Notes made during instructional video learning
1, What is a JVM
definition
Java Virtual Machine, the running environment of JAVA program (the running environment of JAVA binary bytecode)
benefit
- Write once and run everywhere
- Automatic memory management, garbage collection mechanism
- Array subscript out of bounds check
compare
Differences between JVM JRE JDK
2, Memory structure
Overall architecture
1. Program counter
effect
Used to save the address of the next instruction to be executed in the JVM (similar to a register)
characteristic
- Thread private
- The CPU will allocate time slices for each thread. When the time slice of the current thread is used up, the CPU will execute the code in another thread
- The program counter is private to each thread. When the time slice of another thread runs out and returns to execute the code of the current thread, you can know which instruction should be executed through the program counter
- There will be no memory overflow
2. Virtual machine stack
definition
-
The memory space required for each thread is called virtual machine stack
-
Each stack consists of multiple stack frames, corresponding to the memory occupied by each method call
-
Each thread can only have one active stack frame, corresponding to the currently executing method
demonstration
code
public class Main { public static void main(String[] args) { method1(); } private static void method1() { method2(1, 2); } private static int method2(int a, int b) { int c = a + b; return c; } }
It can be seen from the console that the methods in the main class conform to the characteristics of the stack when entering the virtual machine stack
Problem Formulation
- Does garbage collection involve stack memory?
- unwanted. Because the virtual machine stack is composed of stack frames, after the method is executed, the corresponding stack frame will be popped out of the stack. Therefore, there is no need to recycle memory through garbage collection mechanism.
- Is the larger the stack memory allocation, the better?
- no Because the physical memory is certain, the larger the stack memory, the more recursive calls can be supported, but the fewer threads can be executed.
- Are local variables in methods thread safe?
- It is thread safe if local variables within a method do not escape the scope of the method
- If a local variable references an object and escapes the scope of a method, you need to consider thread safety
out of memory
Java.lang.stackOverflowError: stack memory overflow
Cause of occurrence
- Too many stack frames in the virtual machine stack (infinite recursion)
- Each stack frame takes up too much space
Thread running diagnosis
CPU usage too high
- When running some programs in Linux environment, it may lead to excessive CPU consumption. At this time, it is necessary to locate the threads that occupy too much CPU
- top command to see which process is taking up too much CPU
- ps H -eo pid, tid (thread id),% cpu | grep the process number just found through top | further check which thread occupies too much CPU through ps command
- Jstack process id: compare and locate the nid of the thread in the process with the tid just seen through the ps command. Note that the thread id found by jstack is hexadecimal and needs to be converted
3. Local method stack
Some methods with native keywords need JAVA to call local C or C + + methods. Sometimes JAVA can not directly interact with the underlying operating system, so local methods need to be used
4. Pile
definition
Objects created with the new keyword are placed in heap memory
characteristic
- All threads are shared, and the objects in heap memory need to consider thread safety
- There is a garbage collection mechanism
Heap memory overflow
java.lang.OutofMemoryError : java heap space. Heap memory overflow
Heap memory diagnostics
jps
jmap
jconsole
jvirsalvm
5. Method area
structure
out of memory
- Before 1.8, it will cause permanent generation memory overflow
- After 1.8, it will cause meta space memory overflow
Constant pool
Composition of binary bytecode: basic information of class, constant pool, method definition of class (including virtual machine instructions)
Decompile to view class information
-
Get the of the corresponding class Class file
-
Run cmd in the bin directory corresponding to JDK, or enter it on the IDEA console
-
Enter the absolute path of the corresponding javac class
F:\JAVA\JDK8.0\bin>javac F:\Thread_study\src\com\nyima\JVM\day01\Main.java
After input, the class will appear in the corresponding directory Class file
-
-
Enter the absolute path of the javap -v class in the console
javap -v F:\Thread_study\src\com\nyima\JVM\day01\Main.class
-
Then you can see the information of the decompiled class on the console
-
Basic information of class
-
Constant pool
-
The method of executing compilation in the virtual machine (what is in the box is the content of the actual compilation execution, # number content needs to be found in the constant pool)
-
Runtime Constant Pool
- Constant pool
- It is a table (such as constant pool in the figure above). The virtual machine instruction finds the class name, method name, parameter type and literal information to be executed according to this constant table
- Runtime Constant Pool
- The constant pool is After the * class in the class file is loaded, its constant pool information will be put into the runtime constant pool, and the symbolic address in it will be changed into the real address**
Relationship between constant pool and string pool
String pool StringTable
features
- Strings in the constant pool are only symbols and will not be converted to objects until they are used
- The string pool mechanism is used to avoid repeated creation of string objects
- The principle of string variable splicing is StringBuilder
- The principle of string constant splicing is compiler optimization
- You can use the intern method to actively put string objects that are not in the string pool into the string pool
- Note: both strings in the string pool and in the heap are objects
An element that is not used in a repeated string
public class StringTableStudy { public static void main(String[] args) { String a = "a"; String b = "b"; String ab = "ab"; } }
The information in the constant pool will be loaded into the runtime constant pool, but this is a b ab, which is only the symbol in the constant pool and has not become a java string
0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String ab 8: astore_3 9: return
When ldc #2 is executed, the symbol a will be changed into a "a" string object and put into the string pool (hashtable structure cannot be expanded)
When ldc #3 is executed, the symbol b will be changed into a "b" string object and put into the string pool
When ldc #4 is executed, the symbol AB will be changed into "ab" string object and put into string pool
Final StringTable ["a", "b", "ab"]
Note: the creation of string objects is lazy. The string will be created and put into the string pool only when it runs to that line of string and does not exist in the string pool (such as ldc #2).
The process of creating a string using a concatenated string variable object
public class StringTableStudy { public static void main(String[] args) { String a = "a"; String b = "b"; String ab = "ab"; //Splice string objects to create new strings String ab2 = a+b; } }
Decompiled results
Code: stack=2, locals=5, args_size=1 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String ab 8: astore_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_1 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String ;)Ljava/lang/StringBuilder; 20: aload_2 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String ;)Ljava/lang/StringBuilder; 24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/Str ing; 27: astore 4 29: return
The process of creating strings by splicing is: stringbuilder() append(“a”). append(“b”). toString()
The return value of the last toString method is a new string, but the value of the string is consistent with the spliced string, but there are two different strings, one in the string pool and the other in the heap memory
String ab = "ab"; String ab2 = a+b; //The result is false because ab exists in the string pool and ab2 is an object returned by the toString method of StringBuffer and exists in heap memory System.out.println(ab == ab2);
Creates a string using the method of splicing string constant objects
public class StringTableStudy { public static void main(String[] args) { String a = "a"; String b = "b"; String ab = "ab"; String ab2 = a+b; //Create a string using the method of splicing strings String ab3 = "a" + "b"; } }
Decompiled results
Code: stack=2, locals=6, args_size=1 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String ab 8: astore_3 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_1 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String ;)Ljava/lang/StringBuilder; 20: aload_2 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String ;)Ljava/lang/StringBuilder; 24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/Str ing; 27: astore 4 //ab3 gets strings directly from the string pool during initialization 29: ldc #4 // String ab 31: astore 5 33: returnCopy
- When using the method of splicing string constants to create a new string, because the content is a constant, javac will be optimized during compilation. The result has been determined as AB during compilation, and "ab" has been put into the string pool when creating AB, so ab3 directly obtains the value from the string pool, so the operation is the same as ab = "ab".
- When you use the method of splicing string variables to create a new string, because the content is a variable, its value can only be determined at run time, so you need to use StringBuilder to create it
intern method 1.8
Calling the intern method of the string object will try to put the string object into the string pool
- If the string object does not exist in the string pool, it is put successfully
- If there is this string object, it fails to be put in
The string object in the string pool will be returned no matter whether the insertion is successful or not
Note: if the intern method is called successfully at this time, the heap memory and the string object in the string pool are the same object; If it fails, it is not the same object
Example 1
public class Main { public static void main(String[] args) { //"A" and "B" are put into the string pool, and str exists in heap memory String str = new String("a") + new String("b"); //Call the intern method of str. if there is no "ab" in the string pool, the string object will be put into the string pool. At this time, the heap memory and "ab" in the string pool are the same object String st2 = str.intern(); //Assign a value to str3, because there is "ab" in the string pool at this time, the contents in the string pool will be returned directly String str3 = "ab"; //Because the heap memory and "ab" in the string pool are the same object, the following two statements Print true System.out.println(str == st2); System.out.println(str == str3); } }
Example 2
public class Main { public static void main(String[] args) { //The string object "ab" is created here. Because there is no "ab" in the string pool, it is put into the string pool String str3 = "ab"; //"A" and "B" are put into the string pool, and str exists in heap memory String str = new String("a") + new String("b"); //At this time, because "ab" already exists in the string pool when creating str3, putting in fails, but "ab" in the string pool will be returned String str2 = str.intern(); //false System.out.println(str == str2); //false System.out.println(str == str3); //true System.out.println(str2 == str3); } }
intern method 1.6
Calling the intern method of the string object will try to put the string object into the string pool
- If there is no string object in the string pool, a copy of the string object will be copied and put into the string pool
- If there is this string object, it fails to be put in
The string object in the string pool will be returned no matter whether the insertion is successful or not
Note: at this time, the string object in the string pool and the string object in the heap memory are not the same object regardless of whether the intern method is called successfully or not
StringTable garbage collection
When the memory of StringTable is tight, garbage collection will occur
StringTable tuning
-
Because StringTable is implemented by HashTable, the number of HashTable buckets can be appropriately increased to reduce the time required for strings to be put into the string pool
-XX:StringTableSize=xxxx
-
Consider whether you need to pool string objects
You can use the intern method to reduce repeated pooling
6. Direct memory
- It belongs to the operating system and is commonly used in NIO operation. It is used for data buffer
- Allocation recovery cost is high, but read-write performance is high
- Not managed by JVM memory reclamation
Document reading and writing process
DirectBuffer used
Direct memory is an area that can be accessed by both the operating system and Java code. There is no need to copy the code from the system memory to the Java heap memory, which improves the efficiency
Release principle
Direct memory recycling is not released through JVM garbage collection, but through unsafe Freememory to manually release
adopt
//Request 1M of direct memory through ByteBuffer ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1M);
Apply for direct memory, but the JVM cannot recycle the contents of direct memory. How does it recycle?
Implementation of allocateDirect
public static ByteBuffer allocateDirect(int capacity) { return new DirectByteBuffer(capacity); }
DirectByteBuffer class
DirectByteBuffer(int cap) { // package-private super(-1, 0, cap, cap); boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); Bits.reserveMemory(size, cap); long base = 0; try { base = unsafe.allocateMemory(size); //Request memory } catch (OutOfMemoryError x) { Bits.unreserveMemory(size, cap); throw x; } unsafe.setMemory(base, size, (byte) 0); if (pa && (base % ps != 0)) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); //Release the direct memory through virtual reference. this is the actual object of virtual reference att = null; }
Here, a Cleaner's create method is called, and the background thread will also monitor the virtual referenced objects. If the virtual referenced actual objects (DirectByteBuffer in this case) are recycled, Cleaner's clean method will be called to clear the memory occupied in the direct memory
public void clean() { if (remove(this)) { try { this.thunk.run(); //Call the run method } catch (final Throwable var2) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { if (System.err != null) { (new Error("Cleaner terminated abnormally", var2)).printStackTrace(); } System.exit(1); return null; } }); }
run method of corresponding object
public void run() { if (address == 0) { // Paranoia return; } unsafe.freeMemory(address); //Freeing memory occupied in direct memory address = 0; Bits.unreserveMemory(size, capacity); }
Summary of direct memory recycling mechanism
- The Unsafe class is used to complete the allocation and recycling of direct memory. The recycling needs to actively call the freeMemory method
- The implementation of ByteBuffer internally uses Cleaner (Virtual Reference) to detect ByteBuffer. Once ByteBuffer is garbage collected, ReferenceHandler will call Cleaner's clean method and freeMemory to free memory