当前位置:网站首页>In depth analysis of how the JVM executes Hello World
In depth analysis of how the JVM executes Hello World
2022-07-02 09:17:00 【_ Time boiled the rain】
Catalog
Break the parental delegation mechanism
Students who must study computer , The first programs written are Hello World!, At this point, I am glad to open the door of the programming world , So for Java Procedure , How does the program work ?
Let's take a look at the first program we wrote :
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
We usually use them javac command , First the .java The file is compiled as .class file
javac HelloWorld.java
And then use java Command execution .class file , And then it outputs “Hello World!”.
java HelloWorld
Hello World!
We know , stay jdk The installation path bin Under the table of contents , Can find the same name as the command we often execute exe Executable program , such as java、javac、jhat、jinfo......
chart 1
java HelloWorld command , It means using java.exe start-up JVM(Java virtual machine ) Parse and execute our bytecode file ( namely HelloWorld.class), The specific process is as follows :
chart 2
Bytecode file structure
chart 3: Bytecode binary
Every bytecode file ( Including but not limited to *.class text file ) All correspond to the definition information of a unique class or interface .
according to 《Java Virtual machine specification 》,Class File structure definitions can be used C Language ( Pseudo code ) Express :
You can see , The bytecode file contains :
magic: magic number , Fixed value 0xCAFEBABE, Occupy the head 4 Bytes , The only function is to determine whether the file can be accepted by the virtual machine class file
minor_version: Sub version number , Occupy No 5 And the 6 Bytes
major_version: The major version number , Occupy No 7 And the 8 Bytes
constant_pool*: Constant pool information , Mainly including literal quantity ( Such as text string 、final Constant decorated ) And symbol reference ( package 、 Class and interface names 、 Field and method name description, etc ) Two categories:
access_flags: Access signs , This Class Class or interface ; Is it defined as public type ; Is it defined as abstract type ; If it's a class , Is it declared as final;
this_class/super_class/interfaces*: Class index 、 Parent index and interface index set , Used to determine the inheritance relationship of this class
fields*: Field information , Describes variables declared in an interface or class
method*: Methods information 、 Including instance initialization methods and class or interface initialization methods
attribute*: Attribute information 、Class file 、 Field table 、 Attribute table set in method table , such as , What you wrote in the method Java Code , after Javac After the compiler compiles into bytecode instructions , It is stored in the method attribute table set with a name “Code” In the properties of
Types in the structure definition u1、u2、u4、u8, Represent the 1 Bytes 、 2 Bytes 、 4 Bytes and 8 An unsigned number of bytes ; type cp_info、field_info、method_info、attribute_info Represents the corresponding defined structure .
Put the above binary class After the file is converted to hexadecimal , You can see that , The first four bytes are fixed values 0xCAFEBABE, No.. Representing the sub version number 5/6 Bytes are 0x0000, Represents the major version number of 7/8 Bytes is 0x0034, That's decimal 52, according to jdk Version comparison table , You can see that I use java 8 edition .
chart 4: Hexadecimal bytecode
chart 5:Jdk Version comparison table
For the convenience of analysis , We generally do not need to manually parse binary or hexadecimal Class file ,JDK Provides a tool to help us analyze class Bytecode file tool :javap( See the picture 1), have access to javap -v HelloWrold Command analyzes instructions in bytecode , Of course , You can also use IDEA in show bytecode Extension tools ( more IDEA plug-in unit ) Help us view and analyze bytecode file structure :
Classfile /D:/workspace/learnProject/cxy965jvm/target/classes/com/cxy965/HelloWorld.class
Last modified 2022-5-28; size 556 bytes
MD5 checksum d39542245044aa1cf75f2436a116e54c
Compiled from "HelloWorld.java"
public class com.cxy965.HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #23 // Hello World!
#4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #26 // com/cxy965/HelloWorld
#6 = Class #27 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/cxy965/HelloWorld;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 SourceFile
#19 = Utf8 HelloWorld.java
#20 = NameAndType #7:#8 // "<init>":()V
#21 = Class #28 // java/lang/System
#22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
#23 = Utf8 Hello World!
#24 = Class #31 // java/io/PrintStream
#25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V
#26 = Utf8 com/cxy965/HelloWorld
#27 = Utf8 java/lang/Object
#28 = Utf8 java/lang/System
#29 = Utf8 out
#30 = Utf8 Ljava/io/PrintStream;
#31 = Utf8 java/io/PrintStream
#32 = Utf8 println
#33 = Utf8 (Ljava/lang/String;)V
{
public com.cxy965.HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/cxy965/HelloWorld;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello World!
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 5: 0
line 6: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
}
SourceFile: "HelloWorld.java"
We can see clearly from the document ,Class Class name of the file , edition 、 Constant pool information 、 And contains a construction method 、 One main Method , Methods contain descriptive information 、 Access ID and a Code attribute .
With main Methods as an example , You can see the following information :
stack: The depth of the operand stack ,2
locals: Storage space required for local variable table ,1 Two variable slots
args_size: The number of arguments ,1,static Methods from 0 Count , The instance method is from 1 Count , Because there will be 1 Point to object instances (this) Local variables of are passed as parameters
getstatic: Execution instruction Operate on static methods
ldc: Execution instruction take String Constant “HelloWorld” Push from constant pool to top of stack
invokevirtual: call PrintStream Of println Method
return: Method returns
LineNumberTable:Java Source code line number and bytecode line number ( The offset of the bytecode ) The correspondence between , When an exception is thrown , The wrong line number information displayed in the stack is obtained from this
LocalVariableTable: The variables of the local variable table in the stack frame are the same as Java The relationship between variables defined in the source code , When others refer to this method , At the same time, the parameter name will be brought , instead of arg0,arg1
Description information : The return value is void, One String Array type parameter
Access signs :public,static
Code attribute :
stack: The depth of the operand stack ,2
locals: Storage space required for local variable table ,1 Two variable slots
args_size: The number of arguments ,1,static Methods from 0 Count , The instance method is from 1 Count , Because there will be 1 Point to object instances (this) Local variables of are passed as parameters
getstatic: Execution instruction Operate on static methods
ldc: Execution instruction take String Constant “HelloWorld” Push from constant pool to top of stack
invokevirtual: call PrintStream Of println Method
return: Method returns
LineNumberTable:Java Source code line number and bytecode line number ( The offset of the bytecode ) The correspondence between , When an exception is thrown , The wrong line number information displayed in the stack is obtained from this
LocalVariableTable: The variables of the local variable table in the stack frame are the same as Java The relationship between variables defined in the source code , When others refer to this method , At the same time, the parameter name will be brought , instead of arg0,arg1
Bytecode instruction
Every bytecode instruction is A byte Of length 、 An operation code that represents the meaning of a specific operation (opcode) And the following zero or more operands representing the parameters required for this operation (operand) What constitutes a .
stay Java Instruction set of virtual machine , Most instructions contain information about the data type they operate on , And their opcodes have special characters as mnemonics to indicate which data type they serve : i Represents right int Type of data operation , l representative long, s representative short, b representative byte, c representative char, f representative float, d representative double, a representative reference, Such as iload The instruction is used to load from the local variable table int Type data into the operand stack , and fload The command loads float Data of type .
Bytecode instruction comparison , For details, please refer to this article :JVM Instruction mnemonics
Java virtual machine
Java The function of virtual machine is to correctly parse class Every bytecode instruction in the file , And correctly execute the machine operation instructions represented by these instructions .
therefore ,Java Virtual machines are not limited to Java Linguistic , Those that can generate virtual machine specifications after compilation class Bytecode file , Can be Java Virtual machine execution , such as Groovy,JRuby Other languages .
Class loading mechanism
Java The virtual machine transfers data from Class File loaded into memory , And verify the data 、 Transform resolution and initialization , Finally, it can be directly used by virtual machine Java type , This process is called the class loading mechanism of virtual machine .
load : obtain Class File binary stream , Transform the static storage structure it represents into the runtime data structure of the method area , Generate a representation of this class in memory java.lang.Class object , As the access to all kinds of data of this class in method area
verification : Verify file format 、 Metadata 、 Bytecode 、 Correctness of symbol references, etc .
Get ready : Allocate memory for static variables defined in the class and set the initial value of class variables
analysis : Replace symbolic references in the constant pool with direct references
initialization : Initialize the values and other resources specified by class variables for the code , Execute static code block
Class loader
In the loading phase of the class loading mechanism , Will get Class File binary stream , This is actually the function realized by using the class loader , In Figure 2 , The class loaders we have seen are boot class loaders 、 Extend the classloader 、 system class loader . In general ,Java By default, the virtual machine uses the system class loader to load our applications .
In these class loaders , In addition to the boot class loader, the virtual machine is inside itself (C++) Realized , Other loaders are outside the virtual machine ( Inherit java.lang.ClassLoader) Realized , For example jre In the corresponding class library file , Another is that we inherit by ourselves ClassLoader Implemented custom loader .
Compare two classes whether or not “ equal ”, Not only the binary stream data is the same , It must also be loaded by the same class loader to be considered equal .
So many class loaders , So a class , Which class loader loads it ?
Parent delegation model
The process of parental delegation model is : If a class loader receives a class load request , It doesn't try to load the class itself first , Instead, delegate the request to the parent loader to complete , This is true of class loaders at every level , So all load requests should eventually be passed to the top-level boot loader , Only when the parent loader feeds back that it cannot complete the load request ( It did not find the required class in its search scope ) when , The child loader will try to load itself .
java.lang.ClassLoader Source code is as follows
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
One advantage of using the parental delegation mechanism is ,Java With its classloader, the class in has a hierarchical relationship with priority . Such as class java.lang.Object, It's stored in rt.jar In , No matter which class loader wants to load this class , Finally, it is delegated to the startup class loader at the top of the model for loading , therefore Object Classes can be guaranteed to be the same class in various classloader environments of a program . conversely , If you don't use the parental delegation model , If each class loader loads by itself , If the user also wrote a name called java.lang.Object Class , And put it in the program ClassPath in , There will be many different Object class , Java There is no guarantee for the most basic behavior in the type system , The app will be a mess .
such as , We create a package name ourselves java.lang, And create under the package Object class , What's going to happen ?
package java.lang;
public class Object {
public static void main(String[] args) {
System.out.println(" Customize Object class ");
}
}
After operation :
error : In the class java.lang.Object I can't find it in China. main Method , Please put main Method is defined as :
public static void main(String[] args)
otherwise JavaFX The application class must extend javafx.application.Application
Think about it , Why is that ?
Execute our custom Object Of main When the method is used , The application class loader needs to load this class first java.lang.Object, According to the double Pro delegation mechanism , It will request the parent class extension class loader to load , The extended class loader will also request to start the class loader to load ( We already know that ,JVM Startup time , You will first create the boot class loader and load rt.jar Class library ), At this time, the class loader will find that it has stay rt.jar in Loaded this class , And return the information level by level to the application class loader .
We customize Object Class is not loaded , When executed main When the method is used , You will find that you can't find it at all main Method ,rt.jar Medium Object Class has no main Method .
that , What can we do to create Object Class execution does not report an error ?
Break the parental delegation mechanism
We mentioned above , We can customize the classloader , Just inherit java.lang.ClassLoader The class can , There are two core methods in this class :
loadClass: It implements the mechanism of parents' delegation
findClass: Empty implementation method
Then we should break the parental delegation , We just need to delete loadClass Delegate the logic of parent class loading in , And rewrite findClass The method can .
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
in fact , After re executing , The following errors will be reported :
Prohibited package name: java.lang
This is a jvm The protection mechanism of , Cannot create with Java The package name is exactly the same in the core class library , To avoid interference !
边栏推荐
- 2022/2/13 summary
- Microservice practice | fuse hytrix initial experience
- Matplotlib swordsman Tour - an artist tutorial to accommodate all rivers
- Chrome视频下载插件–Video Downloader for Chrome
- The channel cannot be viewed when the queue manager is running
- Cloudreve自建云盘实践,我说了没人能限制得了我的容量和速度
- [go practical basis] how to install and use gin
- 我服了,MySQL表500W行,居然有人不做分区?
- Don't spend money, spend an hour to build your own blog website
- Troubleshooting and handling of an online problem caused by redis zadd
猜你喜欢
西瓜书--第六章.支持向量机(SVM)
微服务实战|原生态实现服务的发现与调用
[staff] time mark and note duration (staff time mark | full note rest | half note rest | quarter note rest | eighth note rest | sixteenth note rest | thirty second note rest)
洞见云原生|微服务及微服务架构浅析
Talk about the secret of high performance of message queue -- zero copy technology
Data type case of machine learning -- using data to distinguish men and women based on Naive Bayesian method
[go practical basis] how to verify request parameters in gin
I've taken it. MySQL table 500W rows, but someone doesn't partition it?
ORA-12514问题解决方法
Solutions to Chinese garbled code in CMD window
随机推荐
「面试高频题」难度大 1.5/5,经典「前缀和 + 二分」运用题
Shengshihaotong and Guoao (Shenzhen) new energy Co., Ltd. build the charging pile industry chain
【Go实战基础】gin 如何自定义和使用一个中间件
oracle修改数据库字符集
Sentinel reports failed to fetch metric connection timeout and connection rejection
微服务实战|负载均衡组件及源码分析
Connect function and disconnect function of QT
Oracle related statistics
Oracle modifies tablespace names and data files
Microservice practice | declarative service invocation openfeign practice
别找了,Chrome浏览器必装插件都在这了
MYSQL安装出现问题(The service already exists)
微服务实战|Eureka注册中心及集群搭建
[staff] time sign and note duration (full note | half note | quarter note | eighth note | sixteenth note | thirty second note)
C Gaode map obtains the address according to longitude and latitude
Webflux responsive programming
QT drag event
【Go实战基础】gin 高效神器,如何将参数绑定到结构体
Cloud computing in my eyes - PAAS (platform as a service)
【Go实战基础】gin 如何绑定与使用 url 参数