In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-09 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces the java virtual machine example analysis, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, the following let the editor take you to understand.
1. Preface (based on JDK1.7)
The so-called jvm, also known as java virtual machine. When we write java programs, we can hardly feel the existence of jvm. We only need to write classes according to the java specification, and then we can run the program. Of course, only when our program appears bug, can we see some jvm error messages on the console, such as memory overflow exception and so on.
The reason why java can cross the platform is because jvm shields the differences between various operating systems. For example, our mobile phone needs to be recharged, but there are many ways to charge. You can directly plug the data cable into the socket to charge, or you can plug the data cable into the USB port of the computer to charge. One is the computer and the other is the socket. Why can you charge the phone? The reason is that there is a data cable shielding the difference between the socket and the computer. For a mobile phone, it cannot see what device is connected to the other end of the data cable. It only knows that electricity is transmitted to itself through the data cable. By the way, this is also the principle of the so-called adapter!
Before you start, make it clear that every java program runs will create an instance of jvm! For example, if I run three programs in eclipse at the same time, three jvm instances will be created. Three programs will run in my own jvm without interfering with each other. When the program is finished, the jvm will be destroyed.
two。 Take a brief look at the class loading process
You all know that it takes several steps for a class to be loaded into jvm. Compile to bytecode file, load, link (verify, prepare, parse), initialize. I'll simply take a look at it with the following diagram.
Here, let's focus on the bytecode file to jvm. Why can the bytecode file be loaded into jvm? What is a classloader? What is the specific process of loading? Link, initialization and what exactly are you doing? What the hell is the Class object? What does the specific structure of jvm look like and what is its use? If you execute a method in a class, what exactly is the process in jvm? Wait, a lot of questions.
Some of these problems know a little bit, some really don't know, anyway, a confused class is loaded successfully, and then we can successfully call those methods, which are usually very comfortable to use, but don't you think it's strange when you think about it?
Anyway, when I first saw jvm, the sentence I most wanted to complain about was: Madde, why? I feel like I'm about to become a hundred thousand whys. Ahem, stop talking nonsense and start learning later!
Let me give you an overview of what these steps have done, there is a general process, and then we will slowly delve into what each step has done!
2.1 compiler compilation
There is nothing to say about this. Because java is a static language, the java file we write will be converted into a special binary code before executing the java program. The compiler is the tool for doing this conversion, and when we write the code, we will report an error before we run the program, and there will be a red line under the code somewhere, and it is the compiler that does this work. And the most important source file, generics, are erased at this stage of compiler compilation, so there is no generics information in the bytecode file.
By the way, dynamic languages, such as Python, we write a python program to run without compiling, it will read the first line of code in the source file to run this line of code, and then read the second line of code, run the second line of code.
2.2 Classification and loading sequence of class loaders
What is a classloader? I have a very vivid example: if the bytecode file is a person, and jvm is the underworld, how do you think people will enter the underworld when they die? I certainly can't find the location of the underworld, so I want to let the black and white impermanence please you to pass, the class loader here is black and white impermanence!
After we have a general idea of the use of classloaders, we will take a casual look at the types and operating principles of classloaders.
By the way, we remember the jdk environment variable that was originally configured. My JAVA_HOME=D:\ java\ jdk1.7
By the way, do you know what a jar bag is? In fact, it is a compressed file format, which is not much different from zip,gz and other compressed formats.
To get to the point, there are four kinds of classloaders: start classloader (Bootstrap ClassLoader): the top-level classloader is written in C++; when we write java programs, the compiler will automatically help us import the commonly used jar package, using this classloader, such as Object,String,Integer under the lang package, which we are most familiar with, can be used directly without the need for us to import manually Which jar packages will be imported specifically? this requires us to configure the environment variable JAVA_HOME. The compiler will look for% JAVA_HOME%\ jre\ lib in the environment variables, and then all the following jar packages will be loaded into memory, not in JVM; and for security reasons, the startup class loader will only load classes whose names start with java, javax, sun, etc.
Extended classloader (Extension ClassLoader): the parent classloader is the startup classloader, which is implemented in the java language and is responsible for loading the jar package under the% JAVA_HOME%\ jre\ lib\ ext path. This does not load automatically, but only when it is needed.
Application class loader (Application ClassLoader): the parent class loader is an extension class loader, implemented in java language, which can also be called a system class loader (System ClassLoader). This class loader is mainly used to load classes we write under the classpath when we write the project, such as all src/main/java/ classes in the maven project
Custom class loader: we need to implement our own class loader, when we need a custom class loader in special cases, we only need to implement the ClassLoader interface, and then override the findClass () method, we can implement a class loader by ourselves, and we can load classes anywhere after implementing the class loader. If I create a new class and put it in any corner of the F disk, I can also specify the classpath to load. Interested friends can try it.
Without considering the custom class loader, you can see that starting, extending, and applying these three loaders are like grandpa, father, and son, so if you want to load a class, which class loader should you choose? There must be something delicious for the son to eat first, but the son is very filial and will give the delicious food to his father. Dad will give it to Grandpa again, Grandpa will try to eat it, and if he sees that the sugar content is too high, he will give it to Dad again, and Dad will also try to eat it, and find that it is not delicious, so he will give it to his son at last. This is the parent delegation mechanism of the classloader. Take a look at a random picture:
2.3.JVM internal structure
In fact, most people are very familiar with JVM, isn't it those pieces? Local method stack, java stack, java stack, method area, pc counter. I'll outline the usefulness of these parts first.
Method area: the class loader actually throws the bytecode file here and parses some information contained in the bytecode file, such as full class name, class variable, method-related information, parent class information, interface and so on.
Since the method area is very important, I draw a sketch at random:
Constant pool (belonging to the method area): because the method area is powerful enough to parse a lot of information in bytecode files, but there may be a lot of constants such as 18, "helloworld", and some symbolic references, constant pools store these things; but what is symbolic references? Let me just say that if there are two classes Animal and Dog, there is a method in the Animal class that looks like this: Dog dog = new Dog () Dog.run () At this time, the problem arises. When loading the Animal class, we found that we need to use the Dog class, and we must have to load the Dog class. Then there are two ways. The first is to pause the loading of the Animal class to load the Dog class, and then to load the Dog class after loading. Second, the Dog class continues to load while loading, but I use xxx to represent all the places in Animal where Dog classes, methods and fields are used. After the Dog class is loaded, I point the xxx to the address corresponding to the Dog class in the method area, and then I will ok. Of course we use the second method, and the xxx we use casually here is a symbolic reference, and the Dog class address in the method area after loading is a direct reference.
Java heap: according to so much information stored in the method area, the Class object of each class will be created here, so this Class object uses reflection the most, so what exactly is this Class object? In fact, you don't have to think too hard to understand, you just think of it as another form of bytecode file in memory, just like rice, the form of expression in rice cooker is rice, and the form of expression in pressure cooker is porridge. If the program runs, it will also create objects in the heap and store them in the heap, and all instance objects of the same type of class share a Class object. I also draw a sketch at random to see the following, so the xx.getClass () of different instance objects of the same class are the same, and according to the obtained Class objects, you can use reflection to create new objects and get methods in them. It can be said that the Class object provides us programmers with a safe channel to manipulate objects in the heap.
Pc register: for multithreading, you can think of this as a counter, one for each thread, which says 1, 2, 3, 4, 5. Recording the line number of each thread executing the code, why remember this line number? Does it hurt when you are idle? Of course not! Because for multithreading, cpu first executes thread 1, then stops, executes thread 2, stops, and executes thread 1. At this point, the question is, how does cpu know where the last thread 1 execution came from? So, this pc register is useful, because each thread has one and records the line number of the current execution. The next time cpu comes, you can continue to execute according to this line number!
Java stack: the object has been created and placed in the heap, and then we call a java method, which opens up a small piece of space in the java stack (commonly known as stack frame). There can be multiple stack frames, because other methods can be called in one method! In short, a method corresponds to a stack frame, in which there are parameters such as the local variables in the method to be run, the return value of the method, and so on. After the execution of this method, the stack frame will be backed out (this is the so-called bullet stack). Then the stack is restored.
Local method stack: I don't know if you have opened the source code of some classes of JDK. Many classes have Native methods (local methods). My understanding is to call some methods implemented in c language or other languages in the operating system.
2.4. Load
We have talked about the types of classloaders and the order in which classloaders are used for so long, and then briefly talked about the internal structure and respective functions of JVM. Now it is the selected classloader to load bytecode files and throw them into the method area of JVM.
Take a casual look at the loading steps with pseudo code, and the parameter name is the full name of the class we passed in:
Public Class loadClass (String name) {try {if (parent! = null) {/ / if there is a parent class loader, delegate the parent class loader to load c = parent.loadClass (name, false);} else {/ / if there is no parent class loader, check whether the class is loaded by the startup class loader, by calling the local method native findBootstrapClass0 c = findBootstrapClass0 (name) }} catch (ClassNotFoundException e) {/ / if neither the parent class loader nor the startup class loader can complete the loading task, call its own loading function c = findClass (name);}
So if I customize a classloader MyClassLoader, I can load a Student class that I randomly placed in the F disk myclass directory under the com.wyq.test package in this way:
MyClassLoader myClassLoader=new MyClassLoader ("F:\\ myclass"); Class c=myClassLoader.loadClass ("com.wyq.test.Student")
Then we get the Class object of this class and we can use reflection to do whatever we want with this class.
2.5. Link
The link is divided into three steps: validation, preparation, and parsing.
Casually talk about what these three steps are about to do, and verify: this step is actually of no great use, that is, a virtual opportunity to check whether there is anything wrong with our bytecode file, specifically, to see if there is something wrong with your bytecode file format. Is there anything wrong with the grammar? Wait
Prepare: allocate memory space to static variables of the class and set initial values; we all know that static variables are placed in the method area. For example, if I have a static variable static int age = 18 in my java class, then this stage will first allocate 4 bytes of memory space, and then set the initial value to 0. All the eight basic data types have initial values.
Parsing: to put it more professionally, during the parsing phase, JVM will replace the symbolic references in the binary data of the class with direct references! How to understand this sentence, please see the constant pool introduced above.
2.6 initialization
Or using the static variable of the preparation phase, according to the bytecode file, overwrite the initial value of the preparation phase with the real value 18.
By the way, the three steps of loading, linking and initialization do not have to be completed in this order, but the starting order is this, but there may be overtaking in the corner during the execution.
3. Example analysis
Here, let's write the simplest example to summarize so much of the above knowledge.
Public class Animal {private int age=18; public void run () {}} publci class Test {public static void main (String [] args) {Animal animal = new Animal (); animal.run ();}}
The steps to run this main method:
1. First, the compiler will compile both classes into bytecode files and put them in your project storage path
The 2.Test class will somehow tell JVM its own class name "Test", and the virtual machine will find your Test.class in some powerful way and put it in that directory.
3. Call the class loader and use the parent delegation mechanism to load the class. In the end, it is not unexpected that the class loader should be used to load the Test.class and load it into the JVM method area in the form of a binary stream.
4. After loading, it will verify whether the Test.class conforms to the specification. If there is no problem, it will parse the loaded Test.class and save a lot of information. Constants and symbolic references are saved in the constant pool. Other things such as access modifiers, full class name, full class name of the direct parent class, method and field information, all static variables except constants. And pointers to class loaders and Class objects are stored outside the constant pool.
5. Through the bytecode saved in the method area, JVM can execute the main () method, which always holds a pointer to the constant pool of Test.
6. When executing the first instruction of the main method, you tell JVM to allocate enough memory for the first type of the Test constant pool; because the main method always holds the constant pool pointer to execute Test, it quickly finds the first item of the constant pool and finds that it is a symbolic reference to the Animal class. Then it will first check the method area to see if the Animal class has been loaded, and if not, find the Animal class Here is a little knowledge of the algorithm, how can the virtual machine find the location of the Animal class as quickly as possible? You can use hash tables, search trees and other algorithms.
7. Load Animal.class into the method area, extract the useful information and save it in the method area, and then replace the symbolic reference of the first type of Test constant pool into a direct reference. Note that no object has been created at this time, and the direct reference points to the address where Animal is located in the method area.
8.JVM allocates enough memory in the heap for creating Animal objects. How can you determine how much memory is appropriate? In fact, JVM is quite awesome, and it has been set up to determine how much heap space a class uses to create an object based on the information stored in the method area.
9. After the object is created, the default initial value of the Animal instance variable is set: age = 0
10. Create a stack frame (with a reference to the Animal object), press it into the java stack, and the first instruction of the main method is executed; remember a method, a stack frame?
11. Then call the java code based on this stack frame to initialize the value of age to the correct value: 18
twelve。 When the run () method is executed through this stack frame, another stack frame is opened up to store all the information inside the run () method.
After the execution of the 13.run () method, release the stack frame; then the execution of main () releases the stack frame; then the program finishes execution and cleans up all objects and method areas in the recycling heap
This is probably such a process, in which the last cleaning and recycling process is actually very important. Because the memory cleaning efficiency of the java stack and method area is very good, we can ignore it. The key point is to clean up memory in the heap. Moreover, because some programs will run for a long time, it is impossible to clean up together after the program has been executed every time. It must be necessary to clean up useless objects in the heap memory while running the program. So how to deal with it? It will involve a lot of algorithms and what is the structure inside the heap, and then we will gradually dig.
Thank you for reading this article carefully. I hope the article "sample Analysis of java Virtual Machine" shared by the editor will be helpful to you. At the same time, I also hope you will support us and pay attention to the industry information channel. More related knowledge is waiting for you to learn!
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: 251
*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.