面试——JVM


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 详细信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值