1、什么是JVM?
JVM是一个可运行Java代码的虚拟计算机,包括一套字节码指令集,一组寄存器,一个栈,一个垃圾回收,堆和一个存储方式栈。JVM 是运行在操作系统之上,并不与操作系统直接交互。
2、运行过程:
我们都知道Java源文件,通过编译器,能够产生相应的.class文件,也就是字节码文件,而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码。
如下:Java 源文件 —— 编译器 —— 字节码文件 —— JVM —— 机器码
每一种平台的解释器是不同的,但是实现的虚拟机是相同的,这就是 Java 跨平台机制。
- 多个程序启动就会存在多个虚拟机实例,随程序的开始和完成而创建和消亡
- 多个虚拟机实例之间数据不能共享
2.1 线程
这里的线程指程序执行过程中的一个线程实体,在Hotspot JVM中的Java 线程与操作系统线程有直接的映射关系。
① 当线程本地存储、缓冲池分配、同步对象、栈、程序计数器等准备好以后,创建一个操作系统线程,随着Java线程的生命周期而变化,OS负责调度所有线程并分配CPU。
② OS线程完成初始化,调用Java线程的run()
方法
③ Java线程结束时,释放绑定OS线程和线程所有资源。
Hotspot JVM 后台运行的主要系统线程
- 虚拟机线程: 等待JVM到达安全点操作出现,这些操作必须在独立的线程中执行,因为当 堆 修改时需要JVM到达安全点。操作主要有 stop-the-world 垃圾回收、线程栈 dump、线程暂停、线程偏向锁解除。
- 周期任务线程: 负责定时器任务(即中断),用来调度周期性操作的执行。
- GC线程: 支持JVM的各种GC活动。
- 编译器线程: 支持在运行时将字节码动态编译成本地平台相关的机器码。
- 信号分发线程: 支持接收发送到JVM的信号并调用适当的JVM方法处理。
2.2 JMM 内存模型
- 私有型内存区域: 生命周期与线程相同,依赖用户线程的创建或结束(在Hotspot JVM中,每个线程都与OS线程直接映射)
- 程序计数器: 唯一不会发生OOM的区域
- 一块很小的内存空间,是当前线程所执行的字节码行号指示器,每一个线程都有一个独立的程序计数器。
- 若正在执行Java方法,计数器记录的是字节码指令的地址(当前指令的地址),若为本地方法(Native Method)则设为空。
- 虚拟机栈: 描述Java方法执行的内存模型。每一个方法执行时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息,栈帧对应着方法的开始到结束的过程。
- 栈帧: 是一个存储数据和部分计算结果的数据结构,同时用来处理动态链接、方法返回值和异常分派等信息,无论如何完成方法(正常或异常)都会随着方法结束而销毁。
- 本地方法栈: 为Native方法服务的栈结构。
- 程序计数器: 唯一不会发生OOM的区域
- 共享型内存区域:
- 方法区(永久代): 存储加载的类信息、常量、静态变量、即时编译后的代码等数据。
- 运行时常量池: 方法区的一部分,主要用于存储在类加载后,编译期产生的字面量和符号引用。
- 类实例区(堆内存): 存储创建的对象和数组的内存区域,是GC最重要的内存区域。
- 方法区(永久代): 存储加载的类信息、常量、静态变量、即时编译后的代码等数据。
- 直接型内存区域: 不受JVM GC管理
2.3 JVM 运行时内存
JVM 堆从GC的角度可以细分为 新生代 和 老年代。
2.3.1 新生代
新生代 在JVM 堆内存中占有 1/3 的空间,老年代占有 2/3 的空间。
新生代区域 可分为三个部分:Eden区(8/10)、ServivorFrom区(1/10)、ServivorTo区(1/10)
- Eden区: Java新对象的存储区域(若新对象过大,则会直接放入老年代区),当该区域内存不足时,则会触发Minor GC 进行新生代区回收