文章目录
JVM主要组成部分有哪些?其作用是什么?
类加载器、运行时数据区、执行引擎、本地库接口
- ClassLoader
- Runtime Data Area
- Execution Engine
- Native Interface
作用:先通过类加载器把Java代码转为字节码,运行时数据区再将字节码加载到内存中,
执行引擎将字节码翻译为底层系统指令,然后交给CPU去执行,其过程需要调用其他语言的本地库接口来实现整个程序的功能。
字节码文件只是JVM的一套指令集规范,是不能直接交给底层操作系统去执行,需要用特定的命令解析器(执行引擎)。
简述下JVM运行时数据区
不同虚拟机的运行时数据区可能会有稍微的不同,但都将遵从Java虚拟机规范,Java虚拟机规范规定的区域分为以下5个部分:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区。
- Program Counter Register:当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都依赖此计数器来完成。
- Java Virtual Machine Stacks:用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- Native Method Stack:作用同上一样,不同在于虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的。
- Java Heap:Java Virtual Machine 中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都再这里分配内存。
- Method Area:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
堆栈的区别是什么?
- 空间大小: 堆大小远大于栈
- 共享性: 堆是线程共享的,栈是线程私有的
- 功能性: 堆是用来存放对象的,栈是用来执行程序的
描述类装载的执行过程
- 加载: 根据查找路径找到相对应的 class 文件并导入。
- 检查: 检查加载的 class 文件的正确性。
- 准备: 给类中的静态变量分配内存空间。
- 解析: 虚拟机将常量池中的符号引用替换成直接引用的过程。
- 初始化: 对静态变量和静态代码块执行初始化工作。
符号引用:理解为一个标示,在直接引用直接指向内存中的地址。
Java中有哪些引用类型?
- 强引用: 发生 GC 时不会被回收。
- 软引用: 在发生内存溢出前会被回收(有用但不是必须的对象)。
- 弱引用: 在下一次 GC 时会被回收(有用但不是必须的对象)。
- 虚引用: 无法通过虚引用获得对象,用 PhantomReference 实现虚引用,其用途是在 GC 时返回一个通知。
垃圾回收算法有哪些?
- 标记 — 清除算法: 标记无用对象,进行清楚回收,就是效率低无法清除垃圾碎片。
- 标记 — 整理算法: 标记无用对象,将所有存活的对象都想一端移动,然后将另一端的内存直接清除掉。
- 复制算法: 按容量划分两块大小相等的内存区域,当一块用完时将活着的对象复制到另一块上,然后将已使用的内存空间一次性清理掉。就是内存使用率低,只有原来的一般。
- 分代算法: 按照对象存活周期的不同将内存划分为几块区域,一般是新生代和老年代,新生代一般使用复制算法,老年代一般使用标记 — 整理算法。
JVM有哪些垃圾回收器?有什么区别?
新生代:Serial、ParNew、Parallel Scavenge
老年代:Serial Old、Parallel Old、CMS
整堆回收器:G1
- Serial: 最早的单线程串行垃圾回收器。
- Serial Old: Serial 垃圾回收器老年版,可作为CMS垃圾回收器的备选方案。
- ParNew: Serial 的多线程版。
- Parallel: 和 PraNew 一样类似多线程的,但这个是以吞吐量优先的收集器,可牺牲等待时间换取系统的吞吐量。
- Parallel Old: Parallel 老年版,Parallel 使用的是复制的内存回收算法,老年版使用的是标记 — 整理的内存回收算法。
- CMS: 以获取最短停顿时间为目标的收集器,适用于 B/S 系统。
- G1: 兼顾吞吐量和停顿时间的 GC 实现,是 JDK9 后的默认 GC 选项。
新生代一般使用复制算法,优点是效率高,缺点是内存利用率低;老年代一般使用标记 — 整理算法。
介绍下 CMS 垃圾回收器
Concurrent Mark-Sweep(并发标记清除) :是以牺牲吞吐量为代价来获取最短回收停顿时间的垃圾回收器。
在启动 JVM 参数上加上 “-XX:+UseConcMarkSweepGC” 来指定使用 CMS 垃圾回收器,它适合在要求服务器响应速度的应用上。
由于它是使用标记 — 清除算法实现的,因此在 GC 时会产生大量的内存碎片,当剩余内存无法满足程序运行要求时,系统将会出现 Concurrent Mode Failure,届时 CMS 会使用 Serial Old 垃圾回收器进行垃圾清除,这时系统的性能就会被降低。
分代垃圾回收器是如何工作的?
新生代和老年代作为分区垃圾回收器的两个分区,新生代的默认空间为 1 /3,老年代的默认空间为 2 / 3。
新生代的默认是复制算法 ,且分为 3 个分区:Eden、To Survivor、From Survivor,其默认的空间比为 8 : 1 : 1。
执行的流程为:
- 将 Eden + From Survivor 存活对象放入 To Survivor 区。
- 清空 Eden 和 From Survivor 区。
- From Survivor 和 To Survivor 区交换,From Survivor 变为 To Survivor,To Survivor 变为 From Survivor。
每次从 From Survivor 到 To Survivor 区移动存活对象时,年龄便+1,到达15岁(默认配置)时升为老年代,其对象也会直接进入老年代。
当老年代的空间占用达到一个值时会触发全局垃圾回收,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。
JVM的调优工具有哪些?
JDK 自带了许多监控工具,位于其 bin 目录下,其中最常用的是以下两款视图监控工具:
- jconsole: 用于对 JVM 中的内存、线程和类等进行监控。
- jvisualvn: JDK 自带的全能分析工具,可分析:内存快照、线程快照、程序死锁、监控内存的变化、GC 变化等。
常用的JVM调优参数
- -Xms2g: 初始化堆大小为2g。
- -Xmx2g: 堆最大内存为2g。
- -XX:NewRatio: 设新生代和老年代内存比例为 1 : 4.
- -XX:SurvivorRatio: 设新生代 Eden 和 Survivor 比例为 8 : 2。
- -XX:+UseParNewGC: 指定使用 ParNew + Serial Old 垃圾回收器组合。
- XX:+UseParallelOldGC: 指定使用 ParNew + ParNew Old 垃圾回收器组合。
- -XX:+UseConcMarkSweepGC: 指定使用 CMS + Serial Old 垃圾回收器组合。
- -XX:+PrintGC: 开启打印 GC 信息。
- -XX:+PrintGCDetails: 开启打印 GC 详细信息。