First, basic knowledge
1. JVM instance: A JVM instance corresponds to a standalone Java program running at the process level.
2. JVM execution engine instances: JVM execution engine instances correspond to threads belonging to the user running the program, which are at the thread level.
3. JVM lifecycle:
JVM instance birth: When a Java program is started, a JVM instance is created.
JVM instance execution: Main () is the starting point for the program’s initial thread, which starts any other threads.
JVM instance death: The JVM exits when all non-daemons in the program terminate; The program can also exit using the Runtime class or System.exit() if the security manager allows it.
Note: There are two kinds of threads inside the JVM: daemons and non-daemons. Main () is a non-daemon thread, and daemons are usually used by the JVM itself. Java programs can also identify the threads they create as daemons.
Any class that has a public static void main(String[] args) function can be used as a starting point for JVM instances
Second, the JVM structure
JVMS can be implemented by different vendors. JVM implementations are necessarily different depending on the vendor, but it is possible to implement cross-platform features thanks to the architecture in which the JVM was designed.
The JVM architecture consists of three parts:
Class Loader subsystem: The Class Loader is used to load Java classes into the Java virtual machine. In general, Java virtual machines use Java classes as follows: Java source programs (.java files) are converted to Java bytecode (.class files) after being compiled by the Java compiler. The classloader is responsible for reading the Java bytecode and converting it into an instance of the java.lang.Class Class. Each such instance is used to represent a Java class. An object of this class is created using the newInstance() method of this instance. The actual situation may be more complex, as Java bytecode may be dynamically generated by a tool or downloaded over a network. The second time you instantiate a Class, however, you instantiate it from the corresponding Class Class newInstance() instead of reading the.class file each time.
Execution Engine
Runtime Data Area:
Java program execution process
Java whole procedure and the process of running is quite tedious, this article through a simple procedure to simply explain the whole process.
As shown in the following figure, Java programs go through two major steps from source file creation to program execution: 1. Source file is compiled into ByteCode by compiler; 2. Because Java programs are both compiled and interpreted by the JVM, Java is called a “semi-interpreted” language.
Three, run time data area
Program Counter Register, Java Stack, Native Method Stack, Method Area, Heap
image.png
Program Counter Register
A program counter is a small memory space that can be viewed as a line number indicator of the bytecode being executed by the current thread. Basic functions such as branching, looping, jumping, exception handling, thread recovery, and so on rely on this counter.
Because multithreading in the Java VIRTUAL machine is implemented by the way threads alternate and allocate processor execution time, at any given moment, one processor (or kernel for multi-core processors) will execute instructions in only one thread. Therefore, in order to restore the thread to the correct execution position after switching, each thread needs to have an independent program counter. Counters between threads do not affect each other and are stored independently. We call this kind of memory area “thread private” memory.
According to the JVM specification, if a thread is executing a non-native method, the program counter stores the address of the instruction that is currently being executed. If the thread executes a native method, the value in the program counter is undefined.
Because the amount of space stored in the program counter does not change with the execution of the program, there is no OutOfMemory (OutOfMemory) for program counters.
Java Stack (VM Stack)
The Java Stack, also known as the Java Virtual Machine Stack (Java Vitual Machine Stack), is an in-memory model for the execution of Java methods.
The Java stack holds stack frames, and each stack frame corresponds to a method being called, Stack frames include Local Variables, the Operand Stack, and references to runtime constant pools of the class to which the current method belongs (the concept of runtime constant pools is covered in the methods section) Pool, method Return Address, and some additional information.
image.png
When a thread executes a method, it creates a corresponding stack frame and pushes the stack frame. When the method completes execution, the stack frame is pushed off the stack.
There are two types of exceptions StackOverFlowError and OutOfMemoneyError. A StackOverFlowError is raised when the thread request stack is deeper than the virtual machine allows. An OutOfMemoneyError is raised if the vm stack cannot be extended to allocate sufficient memory space.
It is thread-private and has the same life cycle as the thread.
Native Method Stack
The native method stack works and works very similar to the Java stack. The difference is simply that the Java stack serves the execution of Java methods, while the Native Method stack serves the execution of Native methods.
The specific implementation methods and data structures developed here are not mandated in the JVM specification, and virtual machines are free to implement them. The HotSopt virtual machine directly combines the native method stack with the Java stack.
Like the virtual stack, the local method stack area throws StackOverflowError and OutOfMemoryError exceptions
Method Area
After JDK8 -JVM runtime data area
The Method Area in JDK7 and earlier versions, like the Java heap, is an Area of memory shared by threads that stores information about classes that have been loaded by the virtual machine, constants, static constants, code compiled by the just-in-time compiler, and so on.
A very important part of the method area is the runtime constant pool, which is a runtime representation of the constant pool for each class or interface that is created after the class or interface is loaded into the JVM. Of course, only the contents of the Class file constant pool can be entered into the runtime constant pool. New constants can also be added to the runtime constant pool at run time, such as the String intern method.
package com.jvm;
import java.util.ArrayList;
import java.util.List;
/ * *
* -xx :MaxPermSize=20M The maximum size of the method area is 20M
* Created by yulinfeng on 7/11/17.
* /
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern()); // keep creating threads
}
}
}
In fact, the above code will run differently in JDK6, JDK7, and JDK8. Because string constants in JDK6 has or stored in a pool area (Permanent) so it will throw an OutOfMemoryError: Permanent Space; If the heap is changed to 20M, OutOfMemoryError:Java Heap space; if the heap is changed to 20M, OutOfMemoryError:Java heap space; In JDK8, the method area is completely removed and replaced with Metaspace, so the virtual machine parameter “-xx :MaxPermSize” has no meaning. In its place are “-xx :MetaspaceSize” and “-xx :MaxMetaspaceSize” etc.
In the JVM specification, method areas are not mandated to implement garbage collection. Many people tend to refer to the method area as a “permanent generation” because the HotSpot VIRTUAL machine implements the method area in a permanent generation so that the JVM’s garbage collector can manage this area in the same way as the heap area without having to design a garbage collection mechanism for it. However, since JDK7, the Hotspot VIRTUAL machine has removed the runtime constant pool from the persistent generation.
Heap (Heap)
The largest chunk of managed memory in the JVM. Created when the VM starts.
The only purpose is to hold object instances, and almost all object instances and arrays are allocated here. (The JVM specification says all, but as JIT compilers evolve and escape analysis matures, some instances may not allocate memory in this area.)
The programmer doesn’t have to worry about space release. Java’s garbage collection mechanism takes care of it automatically, so the heap is the main area of garbage collection management and is also known as the “GC heap”.
The heap is shared by all threads, and there is only one heap in the JVM.
Shallow and deep
Shallow Heap and deep Heap are two important concepts. They describe the amount of memory used by an object structure and the amount of memory that can be freed after an object is recycled by GC.
The Shallow Heap is the amount of memory consumed by an object. In a 32-bit system, an object reference would take up 4 bytes, an int would take up 4 bytes, a long would take up 8 bytes, and each object would take up 8 bytes.
Retained Heap is a slightly more complex concept. To understand deep heap, you first need to understand Retained sets. The reserved set of object A refers to the collection of all objects (including object A itself) that can be released after object A is garbage collected. That is, the reserved set of object A can be regarded as the collection of all objects that can only be accessed directly or indirectly through object A. In layman’s terms, it refers to the collection of objects held only by object A. The deep heap is the sum of the shallow heap sizes of all objects in the reserved set of objects.
For example, object A refers to C and D, object B refers to C and E. So the shallow heap size of object A is only A, excluding C and D, and the actual size of object A is the sum of A, C, and D. The size of A’s deep heap is the sum of A and D. Because object C can be accessed through object B, it is not in the range of object A’s deep heap.