- 为什么我们要学习JVM?
- 学习JVM,能更好的了解程序为什么是这样运作的
- 能够自定义参数,优化JVM,使得我们的程序在JVM中获得更好的性能
- 先来看下大致的流程图
首先我们来创建几个用于测试的类
public class A {
public A() {
System.out.println("Init A class");
}
}
public class B extends A {
public static void main(String[] args) {
B b = new B();
C c = new C();
c.test();
}
}
public class C {
public void test() {
System.out.println("test method");
}
}
-
字节码是什么?为什么有字节码
我们都知道Java是跨平台的,那它为什么能够跨平台,答案就是字节码, 它在操作系统上层封装了JVM,使用的class字节码,对操作系统解耦了。 -
JVM如何使用字节码的
首先我们编写的x.java文件通过打包或者命令的方式编译成了.class文件, JVM可以通过这些.class文件获取到相关的信息,然后用于程序的执行,默认会找到main方法。 -
JVM加载字节码的过程
- 加载
加载是类加载中的一个过程,不是类加载
通过全限定类名获得二进制流 转化成方法区的运行时数据结构
生成一个代表这个类的java Class对象,作为方法区这个类的各种数据入口 - 连接
- 验证
校验.class文件是否符合JVM规范,至少它要能被JVM识别才行 - 准备
为.class文件分配所需的内存,其程序中的变量都会被初始化为 初始值 - 解析
符号引用替换成直接引用 - 初始化
如果有父类,会先初始化父类
会执行static块代码 将程序中的变量,需要真正的赋予值
- 验证
- 使用
- 卸载
- 加载
-
JVM类加载
- 什么时候加载(这个类被用到的时候)
- 类加载器
- 启动类加载器(BootStrap ClassLoader)
- 扩展类加载器(Extension ClassLoader)
- 应用类加载器(Applicaition ClassLoader)
- 自定义加载器
- 双亲委派机制
- 作用(为了保证核心不会被串改,保证同一个文件不会被加载多次)
- 加载时会向上加载
-
JVM运行时数据区域
- 方法区(线程共享)
用于存储类、常量等信息 - 程序计数器(线程私有) 用于存储当前执行指令位置,线程直接切换之后要知道上次执行到哪里了吧?
- 虚拟机栈(线程私有)
存储线程中的局部变量,以及虚拟机方法调用情况,为虚拟机服务 - 本地方法栈 虚拟机使用的到的Native方法,HotShot将虚拟机栈和本地方法栈合二为一
- 堆内存
对象实例开辟的内存空间,对象的实际地址
- 方法区(线程共享)