Skip to content

Java JVM面试题

1. JVM的基本概念

问题:什么是JVM?JVM的作用是什么?

答案

  • JVM(Java Virtual Machine):Java虚拟机,是Java程序运行的环境。
  • 作用
    • 将Java字节码转换为特定平台的机器码并执行。
    • 提供内存管理、垃圾回收、线程管理等功能。
    • 实现平台无关性,一次编写,到处运行。

2. JVM的内存结构

问题:JVM的内存结构是怎样的?

答案

JVM内存结构
├── 堆(Heap)
│   ├── 新生代(Young Generation)
│   │   ├── Eden区
│   │   └── Survivor区(From Survivor、To Survivor)
│   └── 老年代(Old Generation)
├── 方法区(Method Area)
│   ├── 类信息
│   ├── 常量池
│   └── 静态变量
├── 栈(Stack)
│   ├── 局部变量表
│   ├── 操作数栈
│   ├── 动态链接
│   └── 方法出口
├── 程序计数器(Program Counter Register)
├── 本地方法栈(Native Method Stack)
└── 直接内存(Direct Memory)

3. 堆内存

问题:堆内存是如何划分的?

答案

  • 新生代:存放新创建的对象。
    • Eden区:新创建的对象存放在Eden区。
    • Survivor区:经过一次或多次GC后仍然存活的对象存放在Survivor区。
  • 老年代:存放生命周期较长的对象。

4. 垃圾回收算法

问题:JVM中有哪些垃圾回收算法?

答案

  • 标记-清除算法:标记需要回收的对象,然后清除。缺点是产生内存碎片。
  • 复制算法:将存活的对象复制到另一块内存,然后清除原内存。缺点是浪费一半内存。
  • 标记-整理算法:标记需要回收的对象,然后将存活的对象整理到一端,然后清除另一端。
  • 分代收集算法:根据对象存活周期的不同,将内存划分为不同的代,采用不同的收集算法。

5. 垃圾收集器

问题:JVM中有哪些垃圾收集器?

答案

  • Serial收集器:单线程收集器,适合单核CPU。
  • Parallel收集器:多线程收集器,适合多核CPU。
  • CMS收集器:并发标记清除收集器,以最短回收停顿时间为目标。
  • G1收集器:面向服务端的收集器,将堆划分为多个Region,可预测停顿时间。
  • ZGC收集器:低延迟垃圾收集器,停顿时间不超过10ms。
  • Shenandoah收集器:低延迟垃圾收集器,停顿时间不超过10ms。

6. 类加载机制

问题:JVM的类加载机制是怎样的?

答案

  • 加载:查找并加载类的二进制数据。
  • 验证:验证字节码的正确性。
  • 准备:为类的静态变量分配内存并设置默认值。
  • 解析:将符号引用转换为直接引用。
  • 初始化:执行类的初始化代码,包括静态变量赋值和静态代码块。

7. 类加载器

问题:JVM中有哪些类加载器?

答案

  • 启动类加载器(Bootstrap ClassLoader):加载Java核心类,如java.lang.String。
  • 扩展类加载器(Extension ClassLoader):加载Java扩展类,如javax.*包中的类。
  • 应用程序类加载器(Application ClassLoader):加载应用程序的类。
  • 自定义类加载器:用户自定义的类加载器。

8. 双亲委派模型

问题:什么是双亲委派模型?

答案

  • 双亲委派模型:类加载器在加载类时,先委托父类加载器加载,如果父类加载器无法加载,才由自己加载。
  • 作用
    • 保证Java核心类的安全性。
    • 避免类的重复加载。

9. JVM参数

问题:常用的JVM参数有哪些?

答案

  • 内存参数
    • -Xms:初始堆大小。
    • -Xmx:最大堆大小。
    • -Xmn:新生代大小。
    • -XX:MetaspaceSize:元空间初始大小。
    • -XX:MaxMetaspaceSize:元空间最大大小。
  • 垃圾回收参数
    • -XX:+UseSerialGC:使用Serial收集器。
    • -XX:+UseParallelGC:使用Parallel收集器。
    • -XX:+UseConcMarkSweepGC:使用CMS收集器。
    • -XX:+UseG1GC:使用G1收集器。
  • 日志参数
    • -XX:+PrintGCDetails:打印GC详细信息。
    • -XX:+PrintGCTimeStamps:打印GC时间戳。
    • -Xloggc:gc.log:将GC日志输出到文件。

10. JVM调优

问题:如何进行JVM调优?

答案

  • 内存调优
    • 设置合适的堆大小,避免频繁GC。
    • 设置合适的新生代和老年代比例。
    • 设置合适的元空间大小。
  • 垃圾回收调优
    • 选择合适的垃圾收集器。
    • 调整垃圾收集器的参数。
  • 线程调优
    • 设置合适的线程栈大小。
    • 避免创建过多的线程。
  • 监控和分析
    • 使用jstat、jmap、jstack等工具监控JVM。
    • 使用VisualVM、JProfiler等工具分析JVM性能。

11. 内存泄漏

问题:什么是内存泄漏?如何检测和解决?

答案

  • 内存泄漏:程序中不再使用的对象无法被垃圾回收,导致内存占用不断增加。
  • 检测方法
    • 使用jmap查看堆内存使用情况。
    • 使用jhat分析堆转储文件。
    • 使用VisualVM、JProfiler等工具分析内存。
  • 解决方法
    • 及时释放不再使用的对象引用。
    • 使用弱引用、软引用等。
    • 避免使用静态集合。

12. 内存溢出

问题:什么是内存溢出?如何解决?

答案

  • 内存溢出:程序需要的内存超过了JVM分配的内存。
  • 解决方法
    • 增加JVM的内存大小。
    • 优化程序,减少内存占用。
    • 检查是否有内存泄漏。

13. 栈溢出

问题:什么是栈溢出?如何解决?

答案

  • 栈溢出:方法调用层次过深,导致栈空间不足。
  • 解决方法
    • 增加线程栈大小。
    • 优化程序,减少方法调用层次。
    • 避免递归调用。

14. 垃圾回收

问题:垃圾回收的触发条件是什么?

答案

  • Minor GC:当Eden区满了时触发。
  • Full GC:当老年代满了时触发,或者调用System.gc()时触发。

15. 对象的创建过程

问题:对象的创建过程是怎样的?

答案

  1. 类加载:加载、验证、准备、解析、初始化。
  2. 分配内存:在堆中为对象分配内存。
  3. 初始化零值:将对象的内存设置为零值。
  4. 设置对象头:设置对象的类信息、哈希码、GC年龄等。
  5. 执行初始化方法:调用构造方法,初始化对象的字段。

16. 对象的内存布局

问题:对象的内存布局是怎样的?

答案

  • 对象头
    • Mark Word:存储对象的哈希码、GC年龄、锁状态等信息。
    • 类型指针:指向对象的类信息。
  • 实例数据:存储对象的字段值。
  • 对齐填充:保证对象的内存大小是8字节的整数倍。

17. 对象的访问定位

问题:对象的访问定位方式有哪些?

答案

  • 句柄访问:通过句柄池访问对象,优点是对象移动时只需要修改句柄池中的指针。
  • 直接指针访问:通过直接指针访问对象,优点是访问速度快。

18. 字符串常量池

问题:什么是字符串常量池?

答案

  • 字符串常量池:JVM中专门存储字符串常量的区域。
  • 作用
    • 避免重复创建字符串对象。
    • 节省内存空间。

示例

java
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true,指向同一个字符串常量

String s3 = new String("Hello");
String s4 = new String("Hello");
System.out.println(s3 == s4); // false,不同的对象

19. 运行时常量池

问题:什么是运行时常量池?

答案

  • 运行时常量池:JVM在运行时创建的常量池,包含类文件中的常量池和运行时生成的常量。
  • 作用
    • 存储字面量和符号引用。
    • 提高程序性能。

20. 方法区

问题:方法区的作用是什么?

答案

  • 方法区:存储类的信息、常量池、静态变量等。
  • 作用
    • 存储类的结构信息,如字段、方法、构造方法等。
    • 存储常量池,如字符串常量、类名、方法名等。
    • 存储静态变量。

21. 元空间

问题:什么是元空间?

答案

  • 元空间:Java 8引入的,用于替代永久代。
  • 区别
    • 元空间使用本地内存,而永久代使用堆内存。
    • 元空间可以动态调整大小,而永久代大小固定。
    • 元空间不会发生Full GC,而永久代会发生Full GC。

22. 直接内存

问题:什么是直接内存?

答案

  • 直接内存:JVM之外的内存,通过Unsafe类或NIO的ByteBuffer.allocateDirect()方法分配。
  • 作用
    • 避免在Java堆和本地内存之间复制数据。
    • 提高IO性能。

23. JIT编译

问题:什么是JIT编译?

答案

  • JIT(Just-In-Time)编译:将字节码编译成本地机器码,提高程序执行速度。
  • 作用
    • 提高程序执行速度。
    • 根据运行时信息进行优化。

24. C1编译器和C2编译器

问题:C1编译器和C2编译器有什么区别?

答案

  • C1编译器:客户端编译器,编译速度快,优化程度低。
  • C2编译器:服务端编译器,编译速度慢,优化程度高。

25. 分层编译

问题:什么是分层编译?

答案

  • 分层编译:根据方法的执行频率,选择不同的编译器进行编译。
  • 层次
    • 第0层:解释执行。
    • 第1层:C1编译,无profiling。
    • 第2层:C1编译,有限profiling。
    • 第3层:C1编译,完全profiling。
    • 第4层:C2编译。