一、app.java程序运行具体的流程
假设我们现在有app.java这个程序要运行,那么具体的流程到底是怎么样的呢?
我们会先运行 javac app.java, 然后这个程序会被编译,产生了app.class这个file,然后我们会用java app去执行整个程序。下面几幅图解释了这背后发生的事。
步骤一:
这是一个简化的流程:class loader先将开发者编译的app.class和基本的.class文件load到RAM里面,这过程也load了其它基本的.class文件: 比如说,String对应的的.class, collection 的 .class,或者object的 .class文件。
经过了class loader的处理后,产生了byte code instruction, 放到execution engine里面, 然后execution engine会通过Native method calls来执行程序。
步骤二:
这个流程还可以分成3个主要成分去分析
- Loader subsystem
- Runtime data area
- Execution engine
下面会一一介绍每个部分的功能。
(1)Loader subsystem
loader subsystem:
- load:
-
- Application class loader: 主要是load开发者的.class文件
- Bootstrap class loader: load JAVA API 的 .class文件
- link:
-
- Verify, 主要检查class和interface结构的正确性
- Prepare, 用于allocate memory给.class file里面的static variables
- Resolve, 主要是将symbolic reference改成具体的一个值
- initialize:
-
- 主要进行class和interface的初始化
(2)Run time data area
- Method(class) data: 主要用于储存class的定义,另外还有method data, field, 和method的code
- Heap: 主要用于储存程序运行时所产生的Object
- PC Register: 全称是program counter register, 主要用于存放下一个JVM instruction的reference
- JAVA Stack:主要用于储存method运行时的数据,
- Native method stack: 这是native method被执行的地方. Native method就是用别的语言写出来的编程语言
(3)Execution Engine
- Interpreter:主要功能是读bytecode,然后执行相对应的instructions.
- JIT(Just-in-time) Compiler:这个部分主要是用以优化execution engine的性能,一般execution engine会先用interpreter去解释bytecode, 然后执行对应的命令。在很多时候,JIT compliler可以将相类似的bytecode都翻译成native code,然后直接运行。直接执行native code会比bytecode快。
- Hotspot profiler: 这个部分也是用来优化性能的,当某些method被多次使用时,Hotspot这个部分就会用profiler去记录那些method所对应的native code, 这样就可以直接用native code而不是byte code了。
- Garbage collector: 这个部分主要负责内存的管理,当程序中的object不再被用的时候,garbage collector会将其删除。
二、JVM位置
三、JVM体系结构
图示说明:
1.灰色区域不会有垃圾回收;
2.暗黄色区域会发生垃圾回收,99%发生在堆中。
(1)类装载器ClassLoader
负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定
类装载器的运行示意图:
(2)类装载器ClassLoader的类型(4种)
虚拟机自带的加载器(3种)
?启动类加载器(Bootstrap)C++
?扩展类加载器(Extension)Java
?应用程序类加载器(App)Java,也叫系统类加载器,加载当前应用的classpath的所有类
需要进行如下两点说明:
第一点:
sun.misc.Launcher它是一个java虚拟机的入口应用。
? 某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
// 自定义的类
class Demo{
}
public class TestClassLoader {
public static void main(String[] args) {
// 自带的
Object o = new Object();
System.out.println("=============================== Object ClassLoader ===============================");
System.out.println(o.getClass().getClassLoader());
System.out.println("=============================== Demo ClassLoader ===============================");
Demo demo = new Demo();
System.out.println("demo的爷爷 : " + demo.getClass().getClassLoader().getParent().getParent());
System.out.println("demo的爸爸 : " + demo.getClass().getClassLoader().getParent());
System.out.println("demo : " + demo.getClass().getClassLoader());
}
}
程序输出结果:
=============================== Object ClassLoader ===============================
null
=============================== Demo ClassLoader ===============================
demo的爷爷 : null
demo的爸爸 : [email protected]
demo : [email protected]
Process finished with exit code 0
第二点:
自顶向下加载class文件,先到先得。什么意思呢?
举个例子说明:
我们自定义一个String类,和JVM自带的String类再同一个包下,那么此时就会有冲突。此时,我们遵循自顶向下加载原则,对于后加载的class,全部忽略,以防止恶意代码对于源码的修改。
用户自定义加载器 (第4种)
Java.lang.ClassLoader的子类,用户可以定制类的加载方式。
参考链接
本文主要整理自互联网,主要是便于自己复习知识所用,侵权联系删除,以下为原文参考链接!
【1】JVM architecture介绍
【2】尚硅谷jvm教程
原文地址:https://www.cnblogs.com/ch-forever/p/10223763.html