JVM常见八股问题

1.什么是JVM?

回答:JVM 是 Java 虚拟机,负责将 Java 字节码转换为机器码并执行。它提供了内存管理、垃圾回收、线程管理等功能,使得 Java 程序能够在不同操作系统上运行而无需修改。

2.JVM的内存结构是什么?

JVM 内存结构主要包括以下几个部分:
方法区: 存储类的结构信息,如类名、访问修饰符、常量池、字段描述等。
堆区: 存储对象实例,几乎所有的对象都在这里分配内存。
栈区: 每个线程都有一个栈帧,用于存储局部变量、操作数栈、动态链接等。
程序计数器: 每个线程都有一个,用于存储当前线程执行的字节码指令地址。
本地方法栈: 为本地方法(native methods)服务,类似于栈区,但为 JNI 服务。

什么是堆和栈?他们区别是什么?

堆(Heap): 堆是 JVM 中的一块内存区域,用于存储对象实例,所有线程共享这块内存。
栈(Stack): 栈是 JVM 中为每个线程分配的内存区域,用于存储局部变量和方法调用。栈中的数据是线程私有的。
区别: 堆用于存储对象,所有线程共享,而栈用于存储方法调用和局部变量,线程独享。栈中的数据生命周期与方法调用有关,而堆中的对象生命周期与垃圾回收机制有关。

垃圾回收是什么?JVM如何进行垃圾回收?

垃圾回收(Garbage Collection, GC)是 JVM 自动管理内存的一种机制,用于回收不再被引用的对象。JVM 通过标记-清除(Mark-Sweep)、标记-整理(Mark-Compact)、复制(Copying)等算法进行垃圾回收。常见的垃圾收集器有 Serial、Parallel、CMS、G1 等。

什么是类加载器?类加载的过程是怎么样的?

类加载器(ClassLoader): 负责将 Java 字节码文件(.class 文件)加载到 JVM 中。Java 有三种主要的类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)。
类加载过程:
加载: 将字节码文件读入内存,并创建一个 Class 对象。
链接: 包括验证、准备、解析三个阶段。验证字节码的正确性,准备阶段为类变量分配内存并设置初始值,解析阶段将符号引用转换为直接引用。
初始化: 执行类的静态代码块和静态变量赋值。

如何调优JVM的性能?

JVM 调优主要涉及垃圾回收、内存管理和线程管理等方面。常见的调优手段包括:
调整堆内存大小: 通过 -Xms-Xmx 参数设置初始堆内存和最大堆内存。
选择合适的垃圾收集器: 根据应用场景选择合适的垃圾收集器,如 G1、CMS、Parallel 等。
配置新生代和老年代的比例: 通过 -XX:NewRatio 参数调整新生代和老年代的内存比例。
设置垃圾回收的日志输出: 通过XX:+PrintGCDetails 查看垃圾回收的详细日志,帮助分析和调优。

什么是JVM中的安全点(Safepoint)?

安全点是 JVM 执行线程可以安全暂停的位置,通常发生在循环结束、方法调用前后、异常处理等位置。垃圾回收、线程暂停等操作都需要所有线程到达安全点后才能执行。

什么是逃逸分析?

逃逸分析是一种优化技术,用于判断对象的作用域。如果对象没有逃逸出方法的作用域,JVM 可以将该对象分配在栈上,而不是堆上,从而减少垃圾回收的压力。

解释JVM中的双亲委派模型?

双亲委派模型是类加载机制的一部分。当类加载器加载类时,首先会将加载请求委派给父类加载器,只有在父类加载器无法找到该类时,子类加载器才会尝试加载。这种机制确保了 Java 核心类库不会被重复加载,并保证了 Java 的安全性。

JVM中常见的内存泄漏原因有哪些?

虽然 Java 有垃圾回收机制,但内存泄漏仍然可能发生,常见原因包括:
静态集合类: 静态集合类持有对象引用,导致对象无法被回收。
长生命周期对象持有短生命周期对象引用: 导致短生命周期对象不能及时回收。
未关闭的资源: 如数据库连接、文件流等资源未关闭,导致资源占用内存无法释放。

详解JVM垃圾回收机制

垃圾回收机制(Garbage Collection, GC)是 JVM 的核心功能之一,它负责自动管理内存,回收不再使用的对象,避免内存泄漏和内存溢出。

1.为什么需要垃圾回收?

内存管理: Java 使用自动内存管理机制,程序员无需手动释放内存。垃圾回收器通过识别不再被引用的对象并回收其占用的内存,确保程序有足够的可用内存。
防止内存泄漏: 垃圾回收器能有效防止内存泄漏问题,避免因为程序员忘记释放对象而导致的内存消耗增加。

2.JVM内存模型

堆内存: 堆是垃圾回收器管理的主要区域,用于存储对象实例。堆内存划分为年轻代(Young Generation)和老年代(Old Generation)。
年轻代: 分为 Eden 区、Survivor 区(From 和 To)。新生对象通常分配在 Eden 区,当 Eden 区满时触发 Minor GC,存活的对象移至 Survivor 区。
老年代: 存放从年轻代晋升的长期存活对象。当老年代空间不足时,触发 Major GC 或 Full GC。
方法区(Metaspace): 存储类的元数据、常量、静态变量等。方法区在 Java 8 之前称为永久代(PermGen),从 Java 8 开始被移到本地内存中,并命名为 Metaspace。

3.垃圾回收的基本算法

标记-清除算法(Mark-Sweep):
标记阶段: 标记所有可达对象(从根节点开始遍历引用链,标记所有访问到的对象)。
清除阶段: 遍历整个堆内存,清除未标记的对象,回收空间。
优点:简单,能有效回收不再使用的对象。
缺点:容易产生内存碎片,可能导致大对象无法分配。
标记-整理算法(Mark-Compact):
标记阶段: 与标记-清除算法相同,标记所有可达对象。
整理阶段: 将存活对象向堆的一端移动,整理出连续的空闲空间,避免内存碎片问题。
优点:消除了内存碎片,适合老年代的垃圾回收。
缺点:整理过程需要移动对象,性能开销较大。
复制算法(Copying):
工作原理: 将内存分为两块,每次只使用其中一块。当使用的内存块满时,复制存活对象到另一块,然后清空已用的内存块。
优点:没有内存碎片,分配简单快速,适合年轻代的垃圾回收。
缺点:浪费一半的内存空间,内存利用率低。

4.常见的垃圾收集器

Serial 收集器:
单线程收集器,执行垃圾回收时会暂停所有应用线程(“Stop the World”)。
适用于单核 CPU 或者内存较小的场景。
Parallel 收集器(也称为吞吐量优先收集器):
多线程收集器,通过多线程并行执行垃圾回收任务,减少停顿时间。
适用于多核 CPU 环境,追求高吞吐量。
CMS 收集器(Concurrent Mark-Sweep):
目标是减少老年代的停顿时间,通过与应用线程并发执行垃圾回收,减少 Full GC 的停顿时间。
适合对停顿时间敏感的应用,但会产生内存碎片,且需要更多的 CPU 资源。
G1 收集器(Garbage First):
面向服务器应用设计,适合大内存、多处理器的环境。将堆内存划分为多个区域,进行局部的并行回收。
能够在设定的停顿时间内最大化垃圾回收效率,并减少停顿时间。
ZGC 和 Shenandoah:
低停顿垃圾收集器,目标是将垃圾回收的停顿时间降低到毫秒级别或更短。
ZGC 是 Oracle 开发的,Shenandoah 是 RedHat 开发的,两者都适用于大内存、低延迟场景。

5.垃圾回收的触发条件

Minor GC: 当年轻代中的 Eden 区满时触发。Minor GC 速度较快,因为大多数对象在年轻代存活时间短,容易被回收。
Major GC / Full GC: 当老年代满时触发。Major GC 速度较慢,因为需要遍历整个老年代,并可能伴随着 Full GC 清理整个堆空间,包括方法区。

6.垃圾回收的调优

调整堆大小: 通过 -Xms-Xmx 参数调整初始和最大堆内存大小。
选择合适的垃圾收集器: 根据应用需求选择不同的垃圾收集器,如 G1、CMS、Parallel 等。
设置新生代与老年代比例: 通过 -XX:NewRatio 调整新生代与老年代的比例。
调整停顿时间: 通过 -XX:MaxGCPauseMillis 设置垃圾回收的最大停顿时间,特别适合 G1 收集器。

7.常见的垃圾回收日志参数

-XX:+PrintGCDetails:打印详细的 GC 日志信息,包括每次 GC 的类型、发生时间、内存变化等。
-Xloggc:将 GC 日志输出到指定文件,便于分析和调优。

你可能感兴趣的:(jvm,java)