1.JVM运行机制的整体脉络
2019-07-28 本文已影响0人
进读万卷书
JVM系列
1.JVM运行机制的整体脉络
2.JVM的分代模型及对象流动
3.常见的垃圾回收器及算法
4.ParNew和CMS的工作原理
1.JAVA代码是怎么运行?
实例代码,创建一个Test类 ,如下:
public class Test {
public static void main(String[] args) {
system.out.println("hello world!");
}
}
要运行代码经过的流程:Test.java编译->Test.class->类加载器->JVM->代码执行。如下图1-1:
2.类是如何加载,何时加载?
- 一个从加载到使用一般会经历如下过程:
加载->验证->准备->解析->初始化->使用->卸载 - 什么时候会加载一个类:
举个例子,改动上面代码,如下:
public class Test {
public static void main(String[] args) {
User user = new User();
system.out.println("hello world!");
}
}
public class User {
String name;
//set get方法省略
}
程序启动的时候会去加载带main方法的Test.class,当执行main方法,发现需要用到User.class,然后就去加载。所以当用到的时候才会加载一个类,如下图1-2:
3.关于验证,准备,解析,初始化
- 验证阶段:校验加载到内存的".class"文件是否符合JVM规范,防止被人修改过,符合才交给JVM。
- 准备阶段:为class开避内存空间,对类变量(static修饰的变量)赋默认值,比如int类型的则赋值0。
- 解析阶段:虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
-
初始化阶段:执行class的初始化代码,比如一些静态变量的赋值,静态代码块。
注意 当我们初始化一个类的时候,如果它的父类还没初始化,会先初始化父类。
4.类的加载机制?
-
类的加载器
1.启动加载器(BootStrap ClassLoader):主要加载Java安装目录(lib)下的核心类库。
2.扩展类加载器(Extension ClassLoader):主要加载Java安装目录(lib/ext)下的扩展类库。
3.应用加载器(Application ClassLoader): 负责加载指定Classpath环境下的类,就是我们写好的java代码。
4.自定义加载器:跟据特定的需求可以自己自定义类加载器,加载特定目录的类。
5.类加载器的继承关系,如下图1-3:
1-3.png
-
双亲委派机制
原理:当需要加载一个类的时候,当前加载器会委托他的父亲加载,这样一层一层往上抛,抛到最上层,如果父亲加载不了,则往下传,让下面的子类加载,直至到当前类加载器。
为什么要这样:考虑安全因素,以防止核心API库被随意篡改,试想一下,如果我们自己写了一个java.lang.Object类替换掉jdk里面的,被系统加载了,这会产生很大的问题。
总结:先让父亲加载,加载不了再由儿子加载。大致流程如下图1-4:
1-4.png
5.JVM有哪些内存区域,都有什么用?
- 堆:存放实例对象。比如代码new User(),创建的对象就放在堆里面。
- 方法区:存放从".class"文件加载上来的类和一些静态变量。
- 虚拟机栈:存放线程执行方法时的信息,比如方法名,方法变量信息等。
- 程序计数器:记录每个线程执行代码的位置。
-
本地方法栈:存放native方法执行时的信息。
用如下代码,从加载到执行,所使用到的内存区域流程图1-5:
public class Test {
public static void main(String[] args) {
User user = new User();
system.out.println("hello world!");
}
}
public class User {
String name;
//set get方法省略
}
1-5.png
6.为什么会有垃圾回收机制?
如上面的图片,JVM的内存是有限的,程序一直在运行,那么当一个方法执行完成后会怎样?方法会出栈,直接释放内存。但是方法执行期间创建的对象怎么办,现在没有引用它,但它还占用着内存。当越来越多的对象创建,内存很快就不够,那么这时个就需要一个办法把没用的对象清空,释放内存。垃圾回收器就是干这个事情的。当达到一定条件时,会触发垃圾回收。如下图1-6:
1-6.png