Q1【P0】JVM 运行时数据区域划分、线程私有/共享及各自作用
核心答案
- 程序计数器:线程私有,记录当前字节码行号,唯一不出现 OOM。
- 虚拟机栈 :线程私有,存放栈帧(局部变量表、操作数栈、动态链接、方法出口),深度溢出抛
StackOverflowError。 - 本地方法栈:线程私有,为 Native 方法服务。
- 堆:线程共享,存放所有对象实例和数组,GC 主战场,可能 OOM。
- 方法区:线程共享,存储类元数据、常量池、静态变量、方法信息。JDK8 后由**元空间(Metaspace)**实现,使用本地内存。
🔁 Mermaid 流程图
graph TB
subgraph 线程私有
PC[程序计数器]
VMS[虚拟机栈] --> SF[栈帧]
NMS[本地方法栈]
end
subgraph 线程共享
Heap[堆] --> Obj[对象实例]
MA[方法区/元空间] --> Meta[类信息/常量/静态变量]
end
🧩 精简源码(栈溢出示例)
java
public class StackOverflowDemo {
public static void recursive() { recursive(); }
public static void main(String[] args) {
recursive(); // 抛出 StackOverflowError
}
}
Q2【P0】JVM 堆内存结构划分、新生代/老年代比例及对象分配策略
核心答案
- 堆结构:新生代(1/3) + 老年代(2/3)。
- 新生代内部分配:Eden : Survivor From : Survivor To = 8 : 1 : 1。
- 分配流程 :
- 新对象优先在 Eden 区分配。
- Eden 满 → Minor GC → 存活对象移入空闲 Survivor。
- 对象每经历一次 Minor GC 年龄+1,默认 15 晋升老年代。
- 大对象(如长数组)直接进入老年代。
- 老年代满 → Full GC。
🔁 Mermaid 流程图
graph TB
New[新对象] --> Eden[Eden区]
Eden -->|满| MinorGC[Minor GC]
MinorGC --> Survivor[存活对象→Survivor To]
Survivor -->|年龄≥15| Old[晋升老年代]
Old -->|满| FullGC[Full GC]
🧩 精简源码
java
public class HeapAllocTest {
public static void main(String[] args) {
while (true) {
byte[] temp = new byte[1024 * 1024];
}
}
}
// VM参数:-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
Q3【P0】GC 可达性分析算法原理及废弃引用计数的原因
核心答案
- 可达性分析 :从 GC Roots 出发遍历引用链,不可达对象判定为可回收。
- GC Roots 包含:栈引用、静态属性/常量引用、JNI 引用、活跃线程等。
- 引用计数缺陷:无法解决循环引用(如 A→B→A,外部无引用但计数器不为 0),JVM 废弃。
🔁 Mermaid 流程图
graph TB
GC[GC Roots] --> A[对象A]
A --> B[对象B]
B -.->|循环引用| A
C[对象C] -.->|无引用链| D[可回收]
🧩 精简源码(循环引用可回收)
java
class Node { Node next; }
public class CircleRefDemo {
public static void main(String[] args) {
Node a = new Node();
Node b = new Node();
a.next = b; b.next = a;
a = null; b = null;
System.gc(); // 可达性分析可正常回收
}
}
Q4【P0】四种引用类型:强/软/弱/虚引用的区别、回收时机及应用场景
核心答案
- 强引用:默认引用,永不回收(即使 OOM)。
- 软引用:内存不足时回收,适用缓存(图片、大对象)。
- 弱引用:下一次 GC 必回收,适用防止内存泄漏(如 Handler 持有 Activity)。
- 虚引用 :无法获取对象,仅用于监控回收(配合
ReferenceQueue),适用堆外内存释放(如 DirectBuffer)。
🔁 Mermaid 流程图
graph LR
Strong[强引用] -->|永不回收| Soft[软引用] -->|内存不足回收| Weak[弱引用] -->|每次GC回收| Phantom[虚引用]
🧩 精简源码
java
import java.lang.ref.*;
public class RefDemo {
public static void main(String[] args) {
Object strong = new Object();
SoftReference<Object> soft = new SoftReference<>(new Object());
WeakReference<Object> weak = new WeakReference<>(new Object());
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantom = new PhantomReference<>(new Object(), queue);
}
}
Q5【P0】类加载的完整生命周期(7个阶段)及每阶段工作
核心答案
- 加载:读取 class 二进制流,生成 Class 对象。
- 验证:校验字节码合法性。
- 准备:为静态变量分配内存并赋默认零值。
- 解析:将符号引用替换为直接引用。
- 初始化:执行静态代码块,为静态变量赋自定义值。
- 使用:实例化对象、调用方法。
- 卸载:类加载器回收后,卸载类元数据。
🔁 Mermaid 流程图
graph LR
Load[加载] --> Verify[验证] --> Prepare[准备] --> Resolve[解析] --> Init[初始化] --> Use[使用] --> Unload[卸载]
🧩 精简源码(观察初始化阶段)
java
public class ClassInitDemo {
static { System.out.println("静态代码块执行,即初始化阶段"); }
public static void main(String[] args) {
// 触发初始化
}
}
Q6【P0】双亲委派模型原理、执行流程及设计目的
核心答案
- 原理:类加载器收到请求后,先委派给父加载器,层层向上到启动类加载器;父加载器无法加载时,才由子加载器自己加载。
- 流程:自定义 → 应用类加载器 → 扩展类加载器 → 启动类加载器。
- 目的:避免重复加载类、防止核心类库被篡改(沙箱安全)、保证类优先级。
🔁 Mermaid 流程图
graph TD
Custom[自定义类加载器] -->|委托| App[应用类加载器]
App -->|委托| Ext[扩展类加载器]
Ext -->|委托| Boot[启动类加载器]
Boot -->|无法加载| Ext -->|无法加载| App -->|自己加载| Custom
🧩 精简源码(自定义类加载器)
java
public class CustomClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
// 遵循双亲委派
return super.loadClass(name);
}
}
Q7【P0】Minor GC、Major GC、Full GC 的区别及触发时机
核心答案
- Minor GC:只回收新生代,频繁快速,Eden 满触发。
- Major GC:只回收老年代(较少单独出现)。
- Full GC :回收整个堆 + 方法区/元空间,耗时最长。触发条件:老年代空间不足、手动
System.gc()、Minor GC 后晋升对象放不下、元空间满。
🔁 Mermaid 流程图
graph TD
Eden满 --> MinorGC[Minor GC]
Old满 --> FullGC[Full GC]
System.gc() --> FullGC
Metaspace满 --> FullGC
🧩 精简源码
java
public class GcTriggerDemo {
public static void main(String[] args) {
System.gc(); // 建议JVM执行Full GC
}
}
Q8【P0】JVM 三大垃圾回收算法:复制、标记-清除、标记-整理的原理与适用场景
核心答案
| 算法 | 原理 | 优点 | 缺点 | 适用区域 |
|---|---|---|---|---|
| 复制 | 存活对象复制到空闲区,清空原区 | 无碎片,简单 | 内存浪费(双倍空间) | 新生代 |
| 标记-清除 | 标记垃圾后直接清除 | 快,不移动对象 | 产生内存碎片 | 老年代(CMS) |
| 标记-整理 | 标记后存活对象向一端移动,清理边界 | 无碎片,紧凑 | 移动对象开销大 | 老年代(Serial Old) |
🔁 Mermaid 流程图(以标记-整理为例)
graph LR
Before[标记前:存活+垃圾] --> Mark[标记存活对象] --> Compact[向左移动存活对象] --> After[清理边界:无碎片]
🧩 精简源码
算法为 JVM 内置,无特定代码;可通过 GC 日志观察。
Q9【P0】JDK8 废弃永久代改用元空间的原因
核心答案
- 永久代大小固定,容易 OOM(尤其动态生成类场景)。
- 元空间使用本地物理内存,不受 JVM 堆限制,默认无上限。
- 类元数据、常量池、方法信息移入元空间,减少 Full GC 频率。
- 方便热部署、插件化、动态代理等场景。
🔁 Mermaid 流程图
graph LR
JDK7[JDK7:永久代 堆内] -->|JDK8| JDK8[JDK8:元空间 本地内存]
🧩 精简源码
无法代码演示,属于 JVM 底层内存布局变更。
Q10【P0】Android 中常见 JVM 内存泄漏的本质与典型场景
核心答案
- 本质:本应被回收的对象,被 GC Roots 强引用链持有,导致无法回收。
- 典型场景 :
- 静态变量长期持有 Activity/View/Context。
- 匿名内部类(如 Handler、AsyncTask)隐式持有外部类。
- 全局集合(ArrayList、HashMap)未清空。
- 资源未关闭:Cursor、FileInputStream、Bitmap。
- 单例模式中持有 Activity 上下文而非 Application 上下文。
🔁 Mermaid 流程图
graph TD
GC[GC Roots] -->|强引用| Leak[无辜对象] -->|无法回收| MemLeak[内存泄漏] --> OOM
🧩 精简源码(静态持有 Activity)
java
public class StaticLeakDemo {
private static Object sHold;
public static void hold(Object obj) { sHold = obj; }
}
Q11【P0】JVM 虚拟机栈的栈帧组成
核心答案
每个栈帧包含:
- 局部变量表:存储方法参数和局部变量(以 slot 为单位)。
- 操作数栈:存放计算过程中的中间结果。
- 动态链接:指向运行时常量池中该方法的符号引用。
- 方法返回地址:正常或异常退出后的返回点。
- 附加信息:调试信息等。
🔁 Mermaid 流程图
graph TB
subgraph 虚拟机栈
Frame3[栈帧3 方法C]
Frame2[栈帧2 方法B]
Frame1[栈帧1 方法A]
end
subgraph 栈帧详细结构
LV[局部变量表]
OS[操作数栈]
DL[动态链接]
RA[返回地址]
end
Frame1 --> LV & OS & DL & RA
🧩 精简源码(通过 javap 查看)
java
public class StackFrameDemo {
public static void methodA(int a, int b) { int c = a + b; methodB(c); }
private static void methodB(int sum) { System.out.println(sum); }
public static void main(String[] args) { methodA(1,2); }
}
// 命令:javap -c -v StackFrameDemo.class
Q12【P0】JVM 对象创建的完整过程(从 new 到初始化)
核心答案
- 检查类是否已加载、链接、初始化。
- 分配内存(指针碰撞或空闲列表)。
- 初始化对象头(MarkWord、类型指针)。
- 实例数据赋默认零值。
- 执行
<init>构造方法,按程序赋值。
🔁 Mermaid 流程图
graph TD
New[new 对象] --> Check[类加载校验]
Check --> Alloc[分配堆内存]
Alloc --> Header[初始化对象头]
Header --> Zero[实例数据默认零值]
Zero --> Init[执行构造方法]
🧩 精简源码
java
public class ObjectCreateDemo {
public static void main(String[] args) {
User user = new User(); // 触发完整创建流程
}
}
class User { int id; String name; }
Q13【P1】CMS 垃圾收集器的四步执行流程及优缺点
核心答案
- 流程:初始标记(STW) → 并发标记 → 重新标记(STW) → 并发清除。
- 优点:大部分阶段与用户线程并发,低停顿。
- 缺点:标记-清除产生碎片;无法处理浮动垃圾;占用 CPU 高。
🔁 Mermaid 流程图
graph LR
InitMark[初始标记 STW] --> ConMark[并发标记] --> Remark[重新标记 STW] --> ConSweep[并发清除]
🧩 精简源码(指定 CMS 参数)
bash
-XX:+UseConcMarkSweepGC
Q14【P1】G1 垃圾收集器的核心原理与 Region 分区概念
核心答案
- 将堆划分为多个大小相等的 Region,不分固定新生代/老年代。
- 追踪每个 Region 的垃圾堆积价值,优先回收垃圾最多的 Region。
- 可实现可预测停顿,兼顾吞吐量与低延迟。
- JDK9+ 默认垃圾收集器。
🔁 Mermaid 流程图
graph TB
Heap[堆内存] --> R1[Region Eden]
Heap --> R2[Region Survivor]
Heap --> R3[Region Old]
Heap --> R4[Region Humongous]
R1 & R2 & R3 & R4 --> GC[优先回收垃圾最多的Region]
🧩 精简源码
bash
-XX:+UseG1GC
Q15【P1】JVM 对象的内存布局(对象头、实例数据、对齐填充)
核心答案
- 对象头:MarkWord(哈希码、GC 年龄、锁状态) + 类型指针(指向方法区类元信息)。
- 实例数据:对象中各个字段的值。
- 对齐填充:保证对象大小是 8 字节的整数倍。
🔁 Mermaid 流程图
graph LR
Header[对象头] --> Instance[实例数据] --> Padding[对齐填充]
subgraph Header内容
Mark[MarkWord]
Type[类型指针]
end
🧩 精简源码(使用 jol 查看)
java
// 依赖:org.openjdk.jol:jol-core
public class ObjectLayoutDemo {
private int id;
public static void main(String[] args) {
ObjectLayoutDemo obj = new ObjectLayoutDemo();
// System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
Q16【P1】逃逸分析是什么?它能带来哪些优化?
核心答案
- 逃逸分析:分析对象的作用域是否会逃逸出当前方法或线程。
- 优化手段 :
- 栈上分配:未逃逸对象直接在栈上分配,避免堆分配和 GC。
- 标量替换:将对象字段拆分为基本类型,存储在栈上。
- 同步消除:未逃逸对象的锁可以消除(本合集已剔除锁相关内容,仅提及)。
- 效果:降低堆压力,提升性能。
🔁 Mermaid 流程图
graph TD
Obj[创建对象] --> Escape{逃逸分析}
Escape -->|未逃逸| Stack[栈上分配/标量替换]
Escape -->|已逃逸| Heap[堆分配]
🧩 精简源码
java
public class EscapeDemo {
public void test() {
Point p = new Point(1, 2); // 未逃逸,可栈上分配
System.out.println(p.x);
}
class Point { int x,y; Point(int x,int y){this.x=x;this.y=y;} }
}
// VM参数:-XX:+DoEscapeAnalysis -XX:+PrintEscapeAnalysis
Q17【P1】Class 文件常量池、运行时常量池、字符串常量池的区别
核心答案
- Class 常量池 :编译期生成,存在于
.class文件中,存字面量和符号引用。 - 运行时常量池 :类加载后移入方法区(元空间),支持动态添加(如
String.intern())。 - 字符串常量池:JDK7+ 位于堆中,专门缓存字符串字面量,避免重复创建。
🔁 Mermaid 流程图
graph LR
ClassFile[.class文件常量池] -->|类加载| Runtime[运行时常量池 方法区]
StringLiteral[字符串字面量] -->|intern| StringPool[字符串常量池 堆]
🧩 精简源码
java
public class ConstantPoolDemo {
public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1 == s2.intern()); // true
}
}
Q18【P1】Android ART 虚拟机与标准 JVM 的核心区别
核心答案
| 特性 | JVM(HotSpot) | Android ART |
|---|---|---|
| 执行方式 | 解释执行 + JIT | AOT 预编译(5.0-6.0);混合模式(7.0+: 解释+JIT+后台AOT) |
| 字节码 | .class → .jar |
.dex → .oat / .odex |
| GC 算法 | 分代收集(CMS/G1/ZGC) | 并发复制(Concurrent Copying)+ 标记清除 |
| 启动速度 | 较慢 | 更快 |
| 内存占用 | 相对较低 | 略高(AOT 后存储空间) |
🔁 Mermaid 流程图
graph LR
subgraph JVM
Dex1[.dex] --> Interpret[解释执行] --> JIT[JIT编译]
end
subgraph ART
Dex2[.dex] --> AOT[安装期AOT编译] --> Native[本地机器码运行]
end
🧩 精简源码(Android 中观察 ART GC)
java
System.gc(); // logcat 过滤 "art" 查看 GC 信息
Q19【P1】JVM 类初始化的触发时机及不触发的情况
核心答案
- 触发 :
new实例、调用静态方法、访问静态非常量字段、反射Class.forName()、子类初始化触发父类。 - 不触发 :仅声明引用(如
Person p = null;)、访问静态常量(编译期常量)、通过数组引用类。
🔁 Mermaid 流程图
graph TD
Trigger[触发初始化] --> New[new实例]
Trigger --> StaticMethod[调用静态方法]
Trigger --> StaticField[访问静态非常量字段]
Trigger --> Reflect[反射 Class.forName]
Trigger --> SubClass[子类初始化]
NoTrigger[不触发初始化] --> Declare[仅声明变量]
NoTrigger --> Constant[访问静态常量]
NoTrigger --> ArrayRef[数组引用]
🧩 精简源码
java
public class InitTriggerDemo {
public static void main(String[] args) {
Person p = null; // 不会触发初始化
System.out.println(Person.CONST); // 若CONST是编译期常量,也不触发
}
}
class Person {
static { System.out.println("初始化"); }
static final int CONST = 100;
}
Q20【P1】JVM 类卸载需要满足的条件
核心答案
- 该类的所有实例已被回收。
- 加载该类的 Class 对象没有任何引用。
- 加载该类的类加载器已被回收。
三个条件同时满足时,类元数据才会被卸载。
🔁 Mermaid 流程图
graph LR
AllInst[所有实例已回收] --> ClassRef[Class无引用] --> Loader[类加载器已回收] --> Unload[类卸载]
🧩 精简源码(通常需结合自定义 ClassLoader 演示)
java
// 示例难以直接展示,需配合自定义类加载器并清空引用后调用 GC
Q21【P1】Stop-The-World(STW)的概念、触发事件及减少方法
核心答案
- STW:GC 时暂停所有应用线程。
- 触发 STW 的 GC 事件:Minor GC、Full GC、CMS 初始标记和重新标记、G1 初始标记和最终标记。
- 减少方法:使用并发收集器(CMS/G1)、调整新生代大小、减少 Full GC 频率(避免大对象、合理设置元空间)。
🔁 Mermaid 流程图
graph LR
App[应用线程运行] --> GC[触发GC] --> STW[全部暂停 STW] --> Execute[执行GC] --> Resume[恢复所有线程]
🧩 精简源码(通过 JVM 参数观察)
bash
-XX:+PrintGCApplicationStoppedTime -XX:+PrintSafepointStatistics
Q22【P1】SafePoint(安全点)和 SafeRegion(安全区域)的作用
核心答案
- SafePoint:程序执行中的特定位置(如循环末尾、方法返回前),线程在此处暂停以执行 GC 等 VM 操作。
- SafeRegion:一段引用关系不会变化的代码区域(如线程处于 Sleep/Blocked 状态),GC 可安全忽略该线程。
- 作用:保证 GC 时所有线程能快速到达一致状态,避免扫描不稳定的栈。
🔁 Mermaid 流程图
graph TD
Code[代码执行] --> Check{是否达到SafePoint?}
Check -->|是| Pause[暂停线程] --> GC --> Resume[恢复]
Check -->|否| Continue[继续执行]
🧩 精简源码(通过 JVM 参数打印安全点停顿)
bash
-XX:+PrintGCApplicationStoppedTime -XX:+PrintSafepointStatistics
Q23【P1】JVM 参数 -Xms/-Xmx/-Xmn/-XX:MetaspaceSize 含义及 Android 堆设置
核心答案
- -Xms:堆初始大小。
- -Xmx:堆最大大小。
- -Xmn:新生代大小(老年代 = 堆 - 新生代)。
- -XX:MetaspaceSize:元空间触发 Full GC 的阈值。
- Android 设置 :在
AndroidManifest.xml中声明android:largeHeap="true"请求更大堆(具体值因设备而异)。
🔁 Mermaid 流程图
graph TD
Heap[堆] --> Young[新生代 -Xmn] --> Eden[Eden]
Young --> S0[Survivor0]
Young --> S1[Survivor1]
Heap --> Old[老年代]
Meta[元空间] -->|本地内存| NativeMemory
🧩 精简源码(Android 大堆)
xml
<application android:largeHeap="true">
Q24【P1】GC Roots 包含哪些?请列举至少 4 种
核心答案
- 虚拟机栈(局部变量表)中引用的对象。
- 方法区中静态属性引用的对象。
- 方法区中常量引用的对象。
- JNI(Native 方法)引用的对象。
- 活跃线程(Thread 对象)。
- 同步监视器(synchronized 锁对象,本合集已剔除但可作为扩展)。
🔁 Mermaid 流程图
graph TD
GC[GC Roots] --> Stack[栈引用]
GC --> Static[静态属性引用]
GC --> Constant[常量引用]
GC --> JNI[JNI引用]
GC --> Thread[活跃线程]
🧩 精简源码(验证 GC Roots)
java
public class GCRootsDemo {
private static Object staticObj = new Object(); // 静态引用
private static final Object constObj = new Object(); // 常量引用
public void method() {
Object localObj = new Object(); // 栈引用
System.gc(); // 这三者均不会被回收
}
}
Q25【P2】JVM 内存溢出(OOM)的常见触发场景
核心答案
- 堆 OOM:不断创建大对象、集合无限添加、大量 Bitmap。
- 元空间 OOM:动态生成大量类(如热修复、插件化、动态代理)。
- 栈 OOM:递归过深或线程数量过多(线程过多导致栈内存不足)。
- 堆外内存 OOM:Native ByteBuffer、未释放的 Bitmap 像素内存。
🔁 Mermaid 流程图
graph TD
HeapOOM[堆OOM] --> BigObj[大对象/集合无限]
MetaOOM[元空间OOM] --> DynamicClass[动态生成大量类]
StackOOM[栈OOM] --> DeepRecursion[递归深度过大]
NativeOOM[堆外OOM] --> BitmapUnreleased[Bitmap未释放]
🧩 精简源码(堆 OOM 示例)
java
import java.util.ArrayList;
public class HeapOOM {
public static void main(String[] args) {
ArrayList<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // 不断分配1MB数组
}
}
}
// VM参数:-Xms10M -Xmx10M
Q26【P2】符号引用与直接引用的区别?解析阶段做了什么?
核心答案
- 符号引用:编译期字符串形式描述类、方法、字段,无实际内存地址。
- 直接引用:运行时真实内存指针、偏移地址。
- 解析阶段:将符号引用替换为直接引用,绑定真实内存地址。
🔁 Mermaid 流程图
graph LR
Symbol[符号引用 字符串] --> Resolve[解析阶段] --> Direct[直接引用 内存地址/偏移]
🧩 精简源码(概念性)
java
// Java 代码中的方法调用在 class 文件中存为符号引用,运行时转换为直接引用
Q27【P2】JVM 内存分配方式:指针碰撞与空闲列表的区别
核心答案
- 指针碰撞:堆内存规整时,用指针标记分配位置,分配时向后移动指针。效率高。
- 空闲列表:堆内存有碎片时,维护空闲内存列表,分配时遍历找到合适空间。
🔁 Mermaid 流程图
graph TD
Compact[内存规整] --> Pointer[指针碰撞 简单移动指针]
Fragmented[内存碎片] --> FreeList[空闲列表 遍历查找]
Q28【P2】字符串 intern() 方法的底层常量池复用逻辑
核心答案
intern():将字符串放入字符串常量池,如果池中已存在则返回池中引用,否则存入并返回。- 作用:复用字符串对象,节省内存,减少重复创建。
🔁 Mermaid 流程图
graph TD
Intern[调用 intern] --> Check{常量池中是否存在?}
Check -->|存在| Return[返回池中引用]
Check -->|不存在| Add[加入常量池] --> Return2[返回新引用]
🧩 精简源码
java
public class InternDemo {
public static void main(String[] args) {
String s1 = new String("abc").intern();
String s2 = "abc";
System.out.println(s1 == s2); // true
}
}
Q29【P2】Android 中 Bitmap 内存占用与 JVM 堆外内存的关系
核心答案
- 高版本 Android(8.0+)中,Bitmap 的像素数据存放在堆外 Native 内存,不在 JVM 堆内。
- JVM 堆中只保留 Bitmap 对象头引用。
- 堆外内存需要主动调用
recycle()释放,否则会导致 Native 内存泄漏,同样引发 OOM。
🔁 Mermaid 流程图
graph LR
subgraph JVM堆
BitmapObj[Bitmap对象 引用]
end
subgraph Native堆
PixelData[像素数据]
end
BitmapObj --> PixelData
🧩 精简源码(模拟 Bitmap 使用)
java
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large);
// 使用完毕后需及时释放
bitmap.recycle();
Q30【P2】JVM 方法区(元空间)中具体存放哪些内容?
核心答案
- 类版本信息、字段信息、方法信息。
- 运行时常量池。
- 静态变量(JDK7 后移到堆,但逻辑上属于方法区)。
- 即时编译器(JIT)编译后的代码缓存。
- 注解元数据。
🔁 Mermaid 流程图
graph TB
Meta[方法区/元空间] --> ClassInfo[类结构信息 版本/字段/方法]
Meta --> RuntimePool[运行时常量池]
Meta --> Static[静态变量 逻辑上]
Meta --> JITCode[JIT编译代码缓存]
Meta --> Annotation[注解元数据]
Q31【P2】新生代为什么不用标记-清除或标记-整理算法?
核心答案
- 新生代对象存活率极低(约 98% 以上一次性回收),复制算法成本最低(只需复制少量存活对象)。
- 标记-清除会产生碎片,新生代频繁分配回收会导致碎片严重。
- 标记-整理需要移动大量存活对象,开销远大于复制算法。
🔁 Mermaid 流程图
graph LR
Young[新生代 存活率低] --> Copy[复制算法 最优]
Old[老年代 存活率高] --> MarkCompact[标记-整理 更合适]
Q32【P2】JVM 启动类加载器、扩展类加载器、应用类加载器的职责
核心答案
- 启动类加载器(Bootstrap) :加载 JDK 核心类库(
rt.jar等),C++ 实现,无父加载器。 - 扩展类加载器(Extension) :加载
jre/lib/ext下的扩展 jar 包。 - 应用类加载器(Application) :加载
CLASSPATH下的项目类和第三方依赖。
🔁 Mermaid 流程图
graph TD
Boot[启动类加载器] -->|父| Extension[扩展类加载器]
Extension -->|父| App[应用类加载器]
App -->|父| Custom[自定义类加载器]
🧩 精简源码(打印类加载器层级)
java
public class ClassLoaderHierarchy {
public static void main(String[] args) {
ClassLoader cl = ClassLoaderHierarchy.class.getClassLoader();
while (cl != null) {
System.out.println(cl);
cl = cl.getParent();
}
}
}