In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article is about how to parse the JVM virtual machine, the editor thinks it is very practical, so I share it with you to learn. I hope you can get something after reading this article.
What is a JVM virtual machine
First of all, we need to understand what a virtual machine is, why a virtual machine can achieve a boast platform, and what kind of role a virtual machine plays in a computer.
(look up from the bottom)
Looking at the operating system and virtual machine layer above, you can see that JVM is on top of the operating system. He helps us solve the problem of different operation of the operating system, so he can help us to praise the operating system.
What if JVM boasts an operating system?
Then look up and come to the parsable execution file of the virtual machine. The virtual machine implements the boast platform according to the specification of .class.
Up to the language level, different languages can have their own syntax and implementation, but eventually they have to be compiled into a file that meets the .class specification for the virtual machine to execute.
So in theory, any language that wants to use the JVM virtual machine to achieve boast platform operations can generate .class files according to the specification, can use JVM, and achieve "compile once, run multiple times".
What exactly does the virtual machine do for us?
Bytecode specification (.class)
Memory management
The first point has already been mentioned above and will not be repeated.
The second point is memory management, which is what we will talk about next. In the days when there was no JVM, in the CCompact + period, in addition to writing normal business code, there was a large part of the code related to memory allocation and destruction. The slightest carelessness can cause a memory leak. After the use of the virtual machine, the allocation and destruction of memory are managed by the virtual machine.
Relatively, it will definitely cause the virtual machine to take up more memory, and the performance will be worse than that of Cpicket +, but as the virtual machine matures, the performance gap is narrowing.
JVM architecture
The Jvm virtual machine is mainly divided into five modules: class loading subsystem, runtime data area, execution engine, local method interface and garbage collection module.
ClassLoader (class loading)
The loading process of the class consists of the following seven steps:
Load-- > verify-- > prepare-- > parse-- > initialize-- > use-- > uninstall
Among them, connection verification, preparation-parsing can be referred to as connection.
Load 1. Get the binary byte stream of Class 2. 0 through the fully qualified name of Class. Load the binary content of Class into the method area of the virtual machine 3. Generate a java.lang.Class object in memory to represent the Class
There are several ways to get the binary byte stream of Class:
1. Read from zip, such as: read Class file contents 2. 5 from files in jar, war, ear, etc. Get from the network, such as: Applet3. Dynamic generation, such as dynamic agent, ASM framework, etc., are all based on this method. Generated by other files, typically generating the corresponding Class class loader from the jsp file
There are two types of classloaders
Class loader built into the virtual machine
This class loader does not have a parent loader, which is responsible for loading the core class library of the virtual machine. Such as: java.lang.*, etc. The root class loader loads the class library from the directory specified by the system property sun.boot.class.path. The implementation of the root class loader depends on the underlying operating system and is part of the implementation of the virtual machine, which does not inherit the java.lang.ClassLoader class. For example, java.lang.Object is loaded by the root class loader. Its parent class loader is the root class loader. He loads the class library from the directory specified by the java.ext.dirs system properties, or from the jre\ lib\ extsubdirectory (extension directory) of the JDK installation directory. If the user-created JAR file is placed in this directory, the extension class loader will automatically load it. The extension class loader is a pure java class and is a subclass of the java.lang.ClassLoader class. Also known as the application loader, its parent class loader is the extended class loader. He loads the class from the directory specified by the environment variable classpath or the system property java.class.path. It is the default parent loader for a user-defined classloader. The system class loader is a pure java class, which is a java.lang.ClassLoader subclass.
App ClassLoader (system class loader)
Extension ClassLoader (extended class loader)
BootStrap ClassLoader (Root Loader)
User-defined class loader
It must be a subclass of the java.lang.ClassLoader abstract class (which itself is inherited by the custom loader)
Loading method that can be customized by users
Note: the "child parent relationship of the class loader" is not a "child parent inheritance relationship", but a data structure that can be compared to a linked list or tree structure.
Code:
Public class SystemClassLoader {public static void main (String [] args) {ClassLoader classLoader = ClassLoader.getSystemClassLoader (); System.out.println (classLoader); while (classLoader! = null) {classLoader = classLoader.getParent (); System.out.println (classLoader);}} output: sun.misc.Launcher$AppClassLoader@18b4aac2sun.misc.Launcher$ExtClassLoader@7a7b0070null
The method of obtaining the class loader
Method description clazz.getClassLoader (); get the ClassLoader,clazz of the current class as the class object instead of the ordinary object Thread.currentThread (). GetContextClassLoader (); get the ClassLoaderClassLoader.getSystemClassLoader () of the current thread context; get the system's ClassLoaderDriverManager.getCallerClssLoader (); get the caller's ClassLoader / * get the string of the class loader * returned as the BootStrap ClassLoader * / public static void getStringClassLoader () {Class clazz used by null Try {clazz = Class.forName ("java.lang.String"); System.out.println ("java.lang.String:" + clazz.getClassLoader ());} catch (ClassNotFoundException e) {e.printStackTrace ();}} output: java.lang.String: null means to load the parent delegation mechanism using BootStrap ClassLoader (classloader)
In addition to the root loader, when each loader is delegated to load the task, it is the first time to choose its parent loader to perform the loading operation, and finally always let the root class loader try to load. If the loading fails, it will return to load in turn. As long as one loader loads successfully, it will be executed (this is the default class loading mechanism implemented by Oracle's Hotpot virtual machine. And most virtual machines are executed in this way), the whole process is shown in the following figure:
Custom class loader:
Public class FreeClassLoader extends ClassLoader {private File classPathFile; public FreeClassLoader () {String classPath = FreeClassLoader.class.getResource (") .getPath (); this.classPathFile = new File (classPath);} @ Override protected Class findClass (String name) {if (classPathFile = = null) {return null;} File classFile = new File (classPathFile,name.replaceAll ("\\. "," / ") +" .class ") If (! classFile.exists ()) {return null;} String className = FreeClassLoader.class.getPackage (). GetName () + ". + name; Class clazz = null; try (FileInputStream in = new FileInputStream (classFile); ByteArrayOutputStream out = new ByteArrayOutputStream ()) {byte [] buff = new byte [1024]; int len While ((len = in.read (buff))! =-1) {out.write (buff,0,len);} clazz = defineClass (className,out.toByteArray (), 0 e.printStackTrace ());} catch (Exception e) {e.printStackTrace ();} return clazz } / * Test load * @ param args * / public static void main (String [] args) {FreeClassLoader classLoader = new FreeClassLoader (); Class clazz = classLoader.findClass ("SystemClassLoader"); try {Constructor constructor = clazz.getConstructor (); Object obj = constructor.newInstance () System.out.println ("current:" + obj.getClass (). GetClassLoader ()); ClassLoader classLoader1 = obj.getClass (). GetClassLoader (); while (classLoader1! = null) {classLoader1 = classLoader1.getParent (); System.out.println ("parent:" + classLoader1);} SystemClassLoader.getClassLoader ("com.freecloud.javabasics.classload.SystemClassLoader") } catch (Exception e) {e.printStackTrace ();} output: current: com.freecloud.javabasics.classload.FreeClassLoader@e6ea0c6 parent: sun.misc.Launcher$AppClassLoader@18b4aac2 parent: sun.misc.Launcher$ExtClassLoader@1c6b6478 parent: nullcom.freecloud.javabasics.classload.SystemClassLoader: sun.misc.Launcher$AppClassLoader@18b4aac2 check
Verify whether the binary content of a Class is legal
1. Verify the file format to ensure that the file format conforms to the specification of the Class file format. Such as: verify the magic number, version number and so on. two。 Metadata validation to ensure that the semantic description of Class conforms to Java's Class specification. Such as: whether the Class has a parent class, whether it inherits the final class incorrectly, whether it is a legitimate abstract class, and so on. 3. Bytecode verification ensures that the semantics of the program are logical by analyzing the data flow and control flow. For example, verify that type conversion is legal. 4. Symbol reference validation occurs when a symbol reference is converted to a direct reference (the conversion occurs in the parsing phase). For example: verify whether the referenced class, member variables, and methods can be accessed (IllegalAccessError), and whether the current class has corresponding methods, members, etc. (NoSuchMethodError, NoSuchFieldError).
Open any .class file using notepad or text tool and you will see the following bytecode content:
The box on the left shows the magic number: cafe babe (to determine whether this file is a Class file that can be received by a virtual machine) the box on the right shows the version number: 0000 0034 (hexadecimal to decimal to 52 means JDK1.8)
Prepare for
In the preparation phase, the virtual machine allocates memory for Class in the method area and sets the initial value of the static member variable to the default value.
Note that only memory is allocated for the static variable (the static variable is in the method area), and the value of the initialized static variable is the default value of the type it belongs to. For example, the int type is initialized to 0 and the reference type is initialized to null. Even if such a static variable is declared: public static int a = 123; after the preparation phase, the value of an in memory is still 0, and the assignment of 123 is performed in the middle initialization phase, so the value of an is 123 after the corresponding Class object is produced in the initialization phase. Public class Test {private static int a = 1; public static long b; public static String str; static {b = 2; str = "hello world"}} allocates 4 bytes (32 bits) of memory space for static variable an of type int with a default value of 0, and assigns 8 bytes (64 bits) of memory space to static variable b of long class, with a default value of 0 The static variable str of type String is assigned to null by default. Analysis
In the parsing phase, the virtual machine replaces the symbolic references in the constant pool with direct references, and the parsing is mainly aimed at symbolic references such as classes, interfaces, methods, member variables, and so on. After the conversion to a direct reference, the symbol reference verification in the verification phase is triggered to verify whether the direct reference after the conversion can find the corresponding classes, methods, member variables, and so on. It can also be seen here that the various stages of class loading may be staggered in the actual process.
Public class DynamicLink {static class Super {public void test () {System.out.println ("super");}} static class Sub1 extends Super {@ Override public void test () {System.out.println ("Sub1") } static class Sub2 extends Super {@ Override public void test () {System.out.println ("Sub2");}} public static void main (String [] args) {Super super1 = new Sub1 (); Super super2 = new Sub2 (); super1.test (); super2.test ();}}
In the parsing phase, the virtual machine replaces the symbolic reference in the binary data of the class with a direct reference.
Initialization
The initialization phase begins to construct a Class object in memory to represent the class, that is, the process of executing the class constructor (). It should be noted that () is not the same as the constructor that creates an instance of the class ()
1. () what is performed in the method is the operation to assign the static variable, as well as the operation in the static statement block. two。 The virtual machine ensures that the () method of the parent class is executed first. 3. If there is no static statement block and no assignment to the static variable in a class, the virtual machine will not generate a () method for the class. 4. The virtual machine ensures that the execution of the () method is thread-safe. Use
There are two ways that Java programs use classes.
Active use
Passive use
Actively use the seven ways of the class, that is, the initialization time of the class:
1. Create an instance of the class; 2. Access to static variables of a class or interface (no overridden variable inheritance, variables belong to the parent class, not subclasses), or assign values to the static variable (static read/write operation); 3. Call the static method of the class; 4. Reflection (e.g. Class.forName ("com.test.Test")); 5. Initialize a subclass of a class (Chlidren inherits the Parent class, if only one Children class is initialized, then the Parent class is also actively used); 6. The Java virtual machine is marked as the startup class when the virtual machine is started (in other words, the class that contains the main method, and the main method itself is static) 7. Dynamic language support provided by JDK1.7: if the class corresponding to the REF_getStatic,REF_public,REF_invokeStatic handle of the parsing result of the java.lang.invoke.MethodHandle instance is not initialized, initialize
Except for the seven cases mentioned above, other ways of using the Java class are regarded as passive use of the class and will not lead to class initialization. For example, calling the loadClass () method of the ClassLoader class to load a class is not active use of the class and will not lead to class initialization.
Note: initialization is only the third step in the process of loading, connecting, and initializing the above class. passive use does not determine whether the first two steps are used or not, that is, even if passive use does not cause class initialization, but it is possible to load and connect the class. For example, call the loadClass method of the ClassLoader class to load a class, which is not an active use of the class and will not cause the class to initialize. One thing to keep in mind: only when the static variable accessed by the program is actually defined in the current class or interface can it be considered active use of the class or interface. Static variables inherited through subclass calls can be counted as active use of the parent class. Unloading
Class in JVM can be uninstalled (unload) only if the following three conditions are met
1. All instances of this class have been GC, that is, no instance of the Class exists in JVM. two。 The ClassLoader that loaded the class has been GC. 3. The java.lang.Class object of this class is not referenced anywhere. For example, the method of this class cannot be accessed anywhere through reflection. Run-time data area (memory model of virtual machine)
The runtime data area is mainly divided into two parts: thread sharing: method area (constant pool, class information, static constant, etc.), heap (storage instance object) thread monopoly: program counter, virtual machine stack, local method stack program counter (PC register)
A program counter is a small piece of memory space that acts as a line number indicator of the bytecode executed by the current thread. When the bytecode interpreter works in the conceptual model of the virtual machine, the bytecode interpreter selects the next bytecode instruction to be executed by changing the value of this counter. Branch, loop, jump, exception handling, thread recovery and other basic functions all rely on this counter.
Features: 1. If the thread is executing the Java method, this counter records the address of the executing virtual machine bytecode instruction 2. 0. If the Native method is being executed, the technology value is empty (Undefined) 3. 0. This memory region is the only one that does not specify any OutOfMemoryError cases in the Java virtual machine specification public class ProgramCounterJavap {public static void main (String [] args) {int a = 1; int b = 10; int c = 100; System.out.println (a + b * c);}}
Using the javap disassembly tool, you can see the following figure:
The position of the red box in the figure is the offset address of the bytecode instruction. When executed to main (java.lang.String []), the corresponding program counter is created in the current thread and the execution address (contents in the red box) is stored in the counter.
This also shows that the counter changes only the value when the program is running, not as the program needs more space, so there will be no overflow.
Virtual machine stack
A method represents a stack, following the first-in-and-out approach. Each stack is divided into local variable table, Operand stack, dynamic linked list, return address, and so on.
The virtual machine stack is thread isolated, that is, each thread has its own independent virtual machine stack.
Local variables: store method parameters and local variable names defined within the method Operand stack: stack needle instruction set (expression stack) dynamic link: holds a reference to the method to which the pointer belongs in the runtime constant pool. The function is to convert a symbolic reference to a direct reference return address at run time: when the exit method is reserved, the upper-level method execution status information
StackOverflowError of virtual machine stack
If the stack depth requested by a single thread is greater than that allowed by the virtual machine, a StackOverflowError (stack overflow error) will be thrown.
JVM allocates a certain amount of memory (- Xss parameter) to the virtual machine stack of each thread, so the number of stack frames that the virtual machine stack can hold is limited. If the stack frames continue to enter the stack without leaving the stack, it will eventually cause the memory space of the current thread virtual machine stack to be exhausted, such as a recursive function call with no termination condition. The code is shown below:
/ * * StackOverflowError * JVM parameter of the virtual machine stack:-Xss160k * @ Author: maomao * @ Date: 2019-11-12 09:48 * / public class JVMStackSOF {private int count = 0; / * StackOverFlowError * / public void stackLeak () {count++; stackLeak ();} public static void main (String [] args) {JVMStackSOF oom = new JVMStackSOF () Try {oom.stackLeak ();} catch (Throwable e) {System.out.println ("stack count:" + oom.count); e.printStackTrace ();}
Set the virtual machine stack memory size of a single thread to 160K, and after executing the main method, a StackOverflow exception is thrown
Stack count: 771java.lang.StackOverflowError at com.freecloud.javabasics.jvm.JVMStackSOF.stackLeak (JVMStackSOF.java:18) at com.freecloud.javabasics.jvm.JVMStackSOF.stackLeak (JVMStackSOF.java:19) at com.freecloud.javabasics.jvm.JVMStackSOF.stackLeak (JVMStackSOF.java:19) at com.freecloud.javabasics.jvm.JVMStackSOF.stackLeak (JVMStackSOF.java:19) at com.freecloud.javabasics.jvm.JVMStackSOF.stackLeak (JVMStackSOF.java:19)
OutOfMemoryError of virtual machine stack
Unlike StackOverflowError,OutOfMemoryError, it refers to the exception that is thrown when the entire virtual machine stack runs out of memory and no new memory can be applied for.
JVM does not provide configuration parameters to set the memory footprint of the entire virtual machine stack. The maximum memory of the virtual machine stack is roughly equal to "the maximum memory that the JVM process can occupy (depending on the specific operating system)-maximum heap memory-maximum method area memory-program counter memory (negligible)-memory consumed by the JVM process itself". When the maximum memory that can be used by the virtual machine stack is exhausted, an OutOfMemoryError is thrown. You can simulate this exception by constantly opening new threads. The code is as follows:
/ * * java stack overflow OutOfMemoryError * JVM parameters:-Xms20M-Xmx20M-Xmn10M-Xss2m-verbose:gc-XX:+PrintGCDetails * @ Author: maomao * @ Date: 2019-11-12 10:10 * / public class JVMStackOOM {private void dontStop () {try {Thread.sleep (24 * 60 * 60 * 1000);} catch (InterruptedException e) {e.printStackTrace () }} / * run out of Stack memory by constantly creating new threads * / public void stackLeakByThread () {while (true) {Thread thread = new Thread (()-> dontStop ()); thread.start ();}} public static void main (String [] args) {JVMStackOOM oom = new JVMStackOOM () Oom.stackLeakByThread ();}} Local method stack square area (Method Area)
The method area mainly stores the class information, constants, static variables, code compiled by the real-time compiler and other data that have been loaded by the virtual machine.
The values in the normally bright pool are loaded into memory through static method blocks during the class loading phase.
Heap (heap)
For most applications, this area is the largest piece of memory managed by JVM. Thread sharing, mainly to store object instances and arrays. Internally, multiple threads are divided into private allocation buffers (Thread Local Allocation Buffer, TLAB). It can be located in a physically discontinuous space, but logically continuous. It is also the main place that we use in the development process.
The data of Heap is implemented by binary tree, and each assigned address stores the memory address, and the length of the object.
The version of heap before jdk 1.8 is divided into Cenozoic generation, senile belt and permanent generation, but after 1.8, the permanent generation is changed to metaspace, which is similar in essence to the permanent generation. It is the realization of the legal area in JVM specification. The metaspace is not in the virtual machine, but in local memory.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.