目录C/C vs Java 内存管理方法区垃圾回收垃圾判定算法垃圾回收算法Java 四种引用类型默认垃圾收集器版本对应C/C vs Java 内存管理1. C/C手动回收无自动垃圾回收机制对象不再使用时必须手动调用delete释放内存若忘记释放会导致内存泄漏无用对象占着内存不释放长期积累最终引发内存溢出OOM优点灵活可控缺点易出错对程序员要求高。2. Java自动回收GC引入 ** 自动垃圾回收GC** 机制由 JVM 垃圾回收器自动回收不再使用的对象GC 主要负责堆内存回收也会回收方法区效率极低线程私有区域程序计数器、虚拟机栈、本地方法栈随线程生命周期销毁无需 GC优点简化开发避免手动内存管理错误缺点GC 时机不可控STW 可能影响性能。方法区垃圾回收一、类的生命周期类从加载到卸载共 5 个阶段加载类加载器读取.class文件生成Class对象链接验证校验类文件是否符合 JVM 规范准备为静态变量分配内存并赋默认初值如int为 0解析将常量池中的符号引用替换为直接内存地址初始化执行静态代码块为静态变量赋程序定义的初始值使用创建对象、调用方法等卸载类从方法区被垃圾回收即方法区回收的核心动作。二、方法区回收的核心条件面试必考方法区回收的目标是不再使用的类一个类能被卸载必须同时满足以下 3 个条件实例无引用此类及其所有子类的实例对象在堆中已无任何引用即所有实例都被回收类对象无引用该类对应的java.lang.Class对象类元数据对象、类对象在任何地方都未被引用类加载器无引用加载该类的类加载器在任何地方都未被引用。只有 3 个条件全部满足JVM 才会在 Full GC 时卸载该类释放方法区内存。三、方法区回收的特点回收频率极低日常业务中类加载器如系统类加载器、Class对象、实例通常长期被引用很难同时满足 3 个卸载条件因此方法区回收效率远低于堆仅在 Full GC 时才会触发。可触发场景自定义类加载器加载临时类使用完成后主动释放类加载器、Class对象、实例的引用热部署、插件化场景下卸载模块时主动清理所有引用触发类卸载。垃圾判定算法一、核心问题如何判断对象可回收Java 中判断对象是否可回收本质是看对象是否还被有效引用若没有任何引用则视为 “死亡对象”可被 GC 回收。特殊情况循环引用的对象也能被回收前提是没有使用引用计数法。二、两种主流判定算法2.1 引用计数法Reference-Counting基本思路给每个对象维护一个引用计数器当对象被新增引用指向时即有其他对象 / 变量引用它→ 计数器 1当指向该对象的引用失效时如引用变量赋值为 null→ 计数器 -1计数器 0 → 说明无任何对象 / 变量引用它该对象可回收。优点实现简单、判定高效Objective-C、Python 等语言使用。缺点引用 / 去引用都要做加减运算影响性能无法解决循环引用问题如 A 引用 BB 引用 A两者计数器永远不为 0无法回收现状主流 Java 虚拟机如 HotSpot已完全弃用。2.2 可达性分析算法Java 采用核心优势解决了引用计数法的循环引用问题是 Java/C# 等语言的标准算法。基本思路以GC Root集合为起点从上到下遍历所有引用对象能被 GC Root 引用链到达的对象 →存活对象标记为存活无法被到达的对象 →死亡对象标记为垃圾可回收。直观理解不在 GC Root 引用关系网中的对象就是垃圾。可作为 GC Root 的对象静态变量属于类生命周期贯穿程序运行是天然的根引用活动线程正在运行的线程其引用的对象必须保留栈帧中局部变量 / 方法参数方法执行期间的临时引用方法结束后失效JNI 引用Java 本地接口JNI调用的C/C 本地代码中引用的 Java 对象生命周期由本地代码管理注本地代码≠Java 代码是 Java 调用的 C/C 代码。垃圾回收算法一、前置概念STW 与吞吐量1. Stop-the-WorldSTW定义JVM 执行 GC 时暂停所有用户线程仅保留 GC 线程运行直到 GC 完成。特点任何 GC 算法都会触发 STWGC 优化的核心目标就是减少 STW 时长提升系统响应速度。2. 吞吐量公式吞吐量 执行用户代码时间 / (执行用户代码时间 GC 时间)意义吞吐量越高说明 CPU 花在业务代码上的时间越多GC 效率越高。二、三大基础 GC 算法1 标记 - 清除算法Mark-Sweep核心流程标记通过可达性分析标记所有存活对象清除对堆内存从头到尾进行线性便遍历如果发现某个对象没有被标记为可达对象则将其回收。优点基础算法无需额外空间。缺点效率低需要两次遍历堆内存标记 清除内存碎片清除后产生大量不连续内存碎片分配大对象时难以找到连续空间。2 复制算法Copying核心流程将内存分为From 区和To 区大小相等新对象只分配到 From 区GC 时将 From 区所有存活对象复制到 To 区并按顺序排列清空 From 区交换 From/To 角色下次继续分配。优点效率高仅复制存活对象适合存活率低的场景无内存碎片存活对象在 To 区连续排列。缺点内存浪费默认只能使用一半内存不适合高存活率场景存活对象多则复制成本极高。应用新生代Minor GCHotSpot 优化为 Eden 2 个 Survivor8:1:1缓解内存浪费问题。3 标记 - 压缩算法Mark-Compact核心流程标记同标记 - 清除标记所有存活对象压缩将所有存活对象向一端移动按顺序排列清除直接清理边界外的死亡对象。优点无内存碎片无内存浪费内存利用率高。缺点效率低存活对象多则移动成本高比标记 - 清除更耗时。应用老年代常与标记 - 清除混合使用多次标记清除后再压缩减少移动次数。三、分代收集算法Generational Collection不是一个新算法是多种算法的结合。1. 核心思想没有最优算法只有最适合的算法根据对象生命周期将堆分为新生代和老年代分别采用不同算法。2. 新生代Young Gen特点区域小、对象存活率极低朝生夕死90% 以上。算法选择复制算法理由存活对象少复制效率高HotSpot 实现Eden : S0 : S1 8 : 1 : 1仅浪费 10% 内存解决了复制算法的内存浪费问题。3. 老年代Tenured Gen特点区域大、对象存活率极高长期存活。算法选择标记 - 清除 或 标记 - 清除 标记 - 压缩混合理由存活对象多复制算法成本太高混合实现可平衡效率与内存碎片问题。四、算法对比总结对比维度复制算法标记 - 清除算法标记 - 压缩算法内存效率最高仅复制存活中等最低移动 整理内存整齐度最高无碎片最低碎片多中等内存利用率最低浪费空间高高适用场景新生代低存活老年代混合用老年代混合用Java 四种引用类型一、核心概述Java 提供了 4 种引用类型用于控制对象的回收时机。二、四种引用详解1 强引用Strong Reference回收策略永不自动回收只要强引用存在GC 永远不会回收该对象。代码示例User user new User(1, zhangsan); // 强引用 User user1 user; // 新增强引用 user null; // 断开一个强引用 System.gc(); // 强制 GC对象仍不会被回收还有 user1 引用特点默认的引用类型new创建的对象都是强引用只有当所有强引用都断开如赋值为null对象才会成为可回收对象。适用场景日常业务对象保证对象在使用期间不会被意外回收。2 软引用Soft Reference回收策略内存不足时才回收在 OOM 抛出前会将软引用对象列入回收范围进行二次回收。代码示例SoftReferenceUser userSoftRef new SoftReference(new User(1, zhangsan)); User user userSoftRef.get(); // 获取对象 // 内存紧张时GC 会回收该对象再次 get() 会返回 null特点内存充足时和强引用一样保留对象内存不足时优先回收软引用对象避免 OOM。适用场景内存敏感的缓存如本地缓存 EHCache、Netty 缓存缓存对象在内存不足时可被清理释放空间。3 弱引用Weak Reference回收策略发现即回收只要发生 GC无论内存是否充足都会回收只被弱引用关联的对象。代码示例WeakReferenceUser userWeakRef new WeakReference(new User(1, zhangsan)); System.out.println(userWeakRef.get()); // 输出对象 System.gc(); // 触发 GC System.out.println(userWeakRef.get()); // 输出 null对象已被回收特点生命周期极短仅存活到下一次 GC 之前比软引用更 “脆弱”GC 一旦执行就会被回收。适用场景临时对象 / 缓存如 ThreadLocal 底层实现、WeakHashMap避免长期占用内存。4 虚引用Phantom Reference别名幽灵引用、幻影引用回收策略对象回收跟踪无法通过虚引用获取对象实例唯一作用是在对象被回收时收到系统通知。代码示例ReferenceQueueObject queue new ReferenceQueue(); PhantomReferenceObject phantomRef new PhantomReference(obj, queue); obj null; // 解除强引用 System.gc(); // 建议 GC // 对象被回收后phantomRef 会进入 queue可通过 isEnqueued() 判断 boolean isCollected phantomRef.isEnqueued();特点完全无法获取对象实例get()永远返回null必须配合ReferenceQueue使用用于监听回收事件。适用场景对象回收监控 / 资源清理如堆外内存释放、资源泄漏检测。三、四种引用对比表引用类型回收时机核心特点典型场景强引用永不回收除非无引用默认引用类型最安全日常业务对象软引用内存不足 OOM 前回收内存敏感避免 OOM本地缓存、内存敏感缓存弱引用每次 GC 必回收生命周期极短发现即回收ThreadLocal、WeakHashMap虚引用对象被回收时通知无法获取对象仅用于监控回收堆外内存释放、回收监控默认垃圾收集器版本对应JDK 版本默认垃圾收集器组合JDK 7Parallel Scavenge Serial OldJDK 8 及 JDK 7u40Parallel Scavenge Parallel OldJDK 9G1Oracle JDK 17G1OpenJDK 17Shenandoah查看命令java -XX:PrintCommandLineFlags -versionJDK 8-XX:UseParallelGCJDK 17-XX:UseG1GC