1. JVM内存模型

1.1 运行时数据区

  • 程序计数器:线程私有,记录当前线程执行的字节码行号指示器

  • Java虚拟机栈:线程私有,存储栈帧(局部变量表、操作数栈、动态链接、方法出口等)

  • 本地方法栈:为Native方法服务

  • Java堆:所有线程共享,存放对象实例,是GC主要区域

  • 方法区:存储已被加载的类信息、常量、静态变量等

1.2 内存分配策略

  • 对象优先在Eden区分配

  • 大对象直接进入老年代

  • 长期存活的对象进入老年代(默认15次GC后晋升)

  • 动态对象年龄判定(Survivor区中相同年龄对象总大小超过一半,则大于等于该年龄的对象直接进入老年代)

2. 垃圾回收机制

2.1 判断对象是否可回收

  • 引用计数法:简单但无法解决循环引用问题

  • 可达性分析算法:通过GC Roots对象作为起点,判断对象引用链是否可达

2.2 垃圾回收算法

  • 标记-清除:简单但会产生内存碎片

  • 复制算法:将内存分为两块,每次使用一块,回收时将存活对象复制到另一块

  • 标记-整理:标记后让存活对象向一端移动,然后清理边界外内存

  • 分代收集:根据对象存活周期将堆分为新生代和老年代,采用不同算法

2.3 常见垃圾收集器

  • Serial:单线程,适用于客户端应用

  • ParNew:Serial的多线程版本

  • Parallel Scavenge:吞吐量优先的收集器

  • CMS:低停顿时间的收集器,采用标记-清除算法

  • G1:面向服务端的收集器,整体采用标记-整理算法,局部采用复制算法

3. 类加载机制

3.1 类加载过程

  1. 加载:获取类的二进制字节流

  2. 验证:确保Class文件符合规范

  3. 准备:为类变量分配内存并设置初始值

  4. 解析:将符号引用转为直接引用

  5. 初始化:执行类构造器<clinit>()方法

3.2 类加载器

  • 启动类加载器:加载<JAVA_HOME>/lib目录下的类

  • 扩展类加载器:加载<JAVA_HOME>/lib/ext目录下的类

  • 应用程序类加载器:加载用户类路径上的类

  • 自定义类加载器:用户自定义实现

3.3 双亲委派模型

  • 子类加载器先委托父类加载器加载

  • 父类加载器无法完成加载时,子类加载器才尝试自己加载

  • 优点:避免重复加载,保证核心类安全

4. JVM性能调优

4.1 常用JVM参数

  • -Xms:初始堆大小

  • -Xmx:最大堆大小

  • -Xmn:新生代大小

  • -XX:SurvivorRatio:Eden与Survivor区比例

  • -XX:NewRatio:新生代与老年代比例

  • -XX:MaxTenuringThreshold:对象晋升老年代的年龄阈值

4.2 调优工具

  • jps:查看Java进程

  • jstat:监控JVM统计信息

  • jmap:生成堆转储快照

  • jstack:生成线程快照

  • VisualVM:可视化监控工具

  • MAT:内存分析工具

5. 常见面试问题

5.1 JVM内存结构

JVM内存主要分为以下几个区域:

  • 方法区(Method Area):存储类信息、常量、静态变量等数据

  • 堆(Heap):对象实例的存储区域,是GC主要管理的区域

  • 虚拟机栈(VM Stack):线程私有,存储局部变量表、操作数栈等

  • 本地方法栈(Native Method Stack):为本地方法服务

  • 程序计数器(Program Counter Register):线程私有,记录当前线程执行的位置

5.2 对象回收判断

判断对象是否可回收的算法:

  1. 引用计数法:每个对象维护引用计数器,为0时回收。简单但无法解决循环引用问题。

  2. 可达性分析:从GC Roots对象开始遍历引用链,不可达的对象判定为可回收。GC Roots包括:

    • 虚拟机栈中引用的对象

    • 方法区中类静态属性引用的对象

    • 方法区中常量引用的对象

    • 本地方法栈中JNI引用的对象

5.3 垃圾回收算法

标记-清除算法(Mark-Sweep)

  • 过程:标记所有需要回收的对象,然后统一清除

  • 优点:实现简单

  • 缺点:产生内存碎片,效率不高

复制算法(Copying)

  • 过程:将内存分为两块,每次只使用一块,存活对象复制到另一块

  • 优点:无内存碎片

  • 缺点:内存利用率只有50%

标记-整理算法(Mark-Compact)

  • 过程:标记后让存活对象向一端移动,然后清理边界外的内存

  • 优点:无内存碎片,内存利用率高

  • 缺点:移动对象成本高

分代收集算法(Generational Collection)

  • 新生代:使用复制算法(如Serial、ParNew收集器)

  • 老年代:使用标记-清除或标记-整理算法(如CMS、Serial Old收集器)

5.4 CMS与G1收集器比较

CMS(Concurrent Mark Sweep)

  • 特点:以最短回收停顿时间为目标,标记-清除算法

  • 过程

    1. 初始标记(STW)

    2. 并发标记

    3. 重新标记(STW)

    4. 并发清除

  • 优点:并发收集,低停顿

  • 缺点:产生内存碎片,CPU敏感

G1(Garbage-First)

  • 特点:面向服务端应用,整体基于标记-整理,局部基于复制算法

  • 优点

    • 可预测停顿时间

    • 高吞吐量

    • 无内存碎片问题

  • 适用场景:大内存(6GB以上)应用

5.5 双亲委派模型

类加载器层次结构:

  1. 启动类加载器(Bootstrap ClassLoader):加载<JAVA_HOME>/lib目录

  2. 扩展类加载器(Extension ClassLoader):加载<JAVA_HOME>/lib/ext目录

  3. 应用程序类加载器(Application ClassLoader):加载用户类路径

工作流程:子类加载器先委托父类加载器加载,父类无法完成时子类才尝试加载

优点

  • 避免重复加载

  • 保证核心类库安全(如java.lang.Object只能由启动类加载器加载)

5.6 内存泄漏排查

排查步骤:

  1. 监控工具:使用jstat、VisualVM等工具观察内存变化

  2. 堆转储jmap -dump:format=b,file=heap.hprof <pid>

  3. 分析工具:MAT(Memory Analyzer Tool)、JProfiler分析堆转储文件

  4. 常见泄漏点

    • 静态集合类

    • 未关闭的资源(连接、流等)

    • 监听器未注销

    • 不合理的缓存设计

5.7 JVM调优参数

常用参数:

  • 堆内存
    • -Xms:初始堆大小
    • -Xmx:最大堆大小
    • -Xmn:新生代大小
  • GC相关
    • -XX:+UseConcMarkSweepGC:使用CMS收集器
    • -XX:+UseG1GC:使用G1收集器
    • -XX:MaxGCPauseMillis:最大GC停顿时间目标
  • 其他
    • -XX:MetaspaceSize:元空间初始大小
    • -XX:MaxMetaspaceSize:元空间最大大小
    • -XX:+HeapDumpOnOutOfMemoryError:OOM时自动生成堆转储

5.8 线程死锁分析

排查方法:

  1. 获取线程快照jstack <pid> > thread_dump.log

  2. 分析死锁:查找"Found one Java-level deadlock"部分

  3. 工具分析:使用VisualVM、JConsole等工具查看线程状态

  4. 预防措施

    • 按固定顺序获取锁

    • 使用tryLock设置超时

    • 避免嵌套锁

5.9 对象创建过程

  1. 类加载检查:检查类是否已加载

  2. 内存分配

    • 指针碰撞:内存规整时使用

    • 空闲列表:内存不规整时使用

  3. 初始化零值:为对象字段赋默认值

  4. 设置对象头:存储类元数据、GC年龄等信息

  5. 执行<init>方法:按照程序员的意愿初始化对象

5.10 类加载过程

  1. 加载(Loading)

    • 获取类的二进制字节流

    • 将静态存储结构转化为方法区运行时数据结构

    • 生成Class对象作为访问入口

  2. 验证(Verification):确保类文件符合规范

  3. 准备(Preparation):为类变量分配内存并设置初始值

  4. 解析(Resolution):将符号引用转为直接引用

  5. 初始化(Initialization):执行类构造器<clinit>()方法

  6. 使用(Using):程序中使用已加载的类

  7. 卸载(Unloading):从JVM中移除不再需要的类

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐