JVM(Java虚拟机)~
一、认识Java虚拟机
Java虚拟机是一个抽象(虚拟)的计算机,使得您的电脑能够运行 Java 程序,以及其他编译成 Java 字节码的程序
Java代码编译成.class字节码文件 => 在JVM上运行的指令 => JVM把这样的字节码再次翻译成二进制机器指令
引入虚拟机,就可以更好的跨平台,很好的支持不同操作系统和CPU
JVM 的核心作用:
- 内存区域划分
- 类加载机制
- 垃圾回收机制
二、JVM的内存区域划分
每次执行Java程序,本质上就是创建了一个对应的JVM,每个Java进程内部都包含了JVM
JVM运行时数据区
1. 程序计数器
很小的区域,只保存一个数字 => 下一条要执行的Java字节码指令的地址
在内存中,通过软件维护(JVM的源码)
2.栈
1.虚拟机栈
给Java程序使用的栈,维护了方法调用的关系(后进先出)
一个栈帧包括调用方法的实参、方法内部的局部变量、方法结束后要返回的上层方法的位置、返回值等等
2.本地方法栈
给C++代码使用的,因为JVM底层是C++实现的(方法修饰中的native)
3.堆(最大的区域)
存储new对象/普通成员变量
new出来的对象全都放在堆中
4.元数据区
存储类对象/static修饰的成员
.Java文件的时候,编写类/方法 => .class文件
JVM运行的时候,就会把.class文件读取到内存中,还需要一些特定的结构表示
注意:有些情况下,内存会溢出
栈溢出:包含的方法调用关系太多了(栈帧)
堆溢出:new的对象太多了
上面这些内存区域,针对程序计数器和栈是存在多份的(每个线程都有自己的),而对于堆和元数据区,一个进程中只有一份(new出来的对象,是可以直接被另一个线程使用的)
三、JVM的类加载机制
把.class文件读取放到内存中,构建出类对象过程
1.类加载的流程
- 加载
把.class文件找到,打开文件,并且读取文件的数据到内存当中,根据代码中的全限定类名,找到对应的.class文件 - 验证
确保加载的字节流符合 JVM 规范,并且不会危害虚拟机自身的安全 - 准备
为类的静态变量分配内存,并设置默认的初始值,在元数据区,Java默认把新申请的,未初始化的内存全都置为0,此时static成员的值也是0 - 针对字符串常量初始化
把当前的.class中的字符串常量,也放到内存中 - 初始化
针对类对象进行初始化操作,初始化类的静态成员,执行静态代码块,对父类的加载
什么时候会加载某个类???
懒汉思想,用的时候再加载
1.new这个对象的实例
2.调用这个类的静态方法/访问静态成员
3.针对某个子类的加载,会触发父类的加载
2.双亲委派模型
出现在类加载的第一步,用来找.class文件,涉及到一个模块,称为类加载器,JVM中包含3个类加载器
- 启动类加载器 (Bootstrap CL)
负责加载Java标准库中的类 - 扩展类加载器 (Extension CL)
负责加载Java扩展库中的类 - 应用程序类加载器 (Application CL)
负责加载第三方库/当前项目中的类
双亲委派模型,约定了类加载的优先级
标准库最先加载,其次是扩展库,最后是第三方库/当前项目