元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
JVM架构
类加载器机制
运行时数据区
执行引擎工作原理
JIT编译器优化
▶
内存管理
垃圾回收算法
分代收集机制
内存分配策略
内存泄漏诊断
▶
并发编程
线程池实现原理
synchronized锁优化
AQS框架解析
并发集合类原理
▶
字节码技术
字节码指令集解析
ASM操作指南
动态代理实现
字节码验证机制
▶
性能调优
JVM参数解析
GC日志分析
堆内存诊断
JIT性能优化
发布时间:
2025-03-22 09:28
↑
☰
# Java垃圾回收算法 Java的垃圾回收(Garbage Collection,GC)是JVM自动管理内存的核心机制。本文将详细介绍Java中的各种垃圾回收算法,包括其工作原理、优缺点及适用场景。 ## 垃圾回收基础 ### 1. 什么是垃圾回收 垃圾回收是一种自动内存管理机制,主要完成以下工作: - 识别哪些内存是垃圾 - 回收垃圾占用的内存 - 整理内存碎片(可选) ### 2. 对象存活判断 ```java public class GCRootDemo { public static void main(String[] args) { // GC Roots示例 Object localVar = new Object(); // 局部变量 static Object staticVar = new Object(); // 静态变量 // 不可达对象 new Object(); // 这个对象没有引用,是垃圾 } } ``` 判断对象是否存活的算法: 1. 引用计数法 - 优点:实现简单 - 缺点:无法解决循环引用 2. 可达性分析 - 从GC Roots开始搜索 - 可达对象都是存活的 - 不可达对象是垃圾 ## 标记-清除算法 ### 1. 基本原理 ```java public class MarkSweepDemo { public static void main(String[] args) { List<byte[]> list = new ArrayList<>(); // 分配一些对象 for (int i = 0; i < 100; i++) { list.add(new byte[1024]); // 1KB } // 清除引用,使对象成为垃圾 list.clear(); // 这里可能会触发标记-清除GC } } ``` 算法步骤: 1. 标记阶段:标记所有可达对象 2. 清除阶段:回收不可达对象 优缺点: - 优点:实现简单 - 缺点:产生内存碎片 ## 复制算法 ### 1. 工作原理 ```java public class CopyingDemo { public static void main(String[] args) { // 模拟Eden区对象分配 byte[] allocation1 = new byte[1024 * 1024]; // 1MB byte[] allocation2 = new byte[1024 * 1024]; byte[] allocation3 = new byte[1024 * 1024]; // 这些对象可能会被复制到Survivor区 } } ``` 算法步骤: 1. 将内存分为两块 2. 只使用其中一块 3. 存活对象复制到另一块 4. 清理原有空间 应用场景: - 新生代垃圾回收 - Eden区和Survivor区 ## 标记-整理算法 ### 1. 算法流程 ```java public class MarkCompactDemo { public static void main(String[] args) { // 模拟老年代对象 List<Object> oldGen = new ArrayList<>(); for (int i = 0; i < 1000; i++) { oldGen.add(new byte[1024 * 1024]); // 1MB if (i % 100 == 0) { oldGen.subList(0, i/2).clear(); // 制造内存碎片 } } } } ``` 算法步骤: 1. 标记阶段:标记存活对象 2. 整理阶段:移动对象,消除碎片 3. 清理阶段:回收垃圾空间 适用场景: - 老年代垃圾回收 - 大对象区域 ## 分代收集算法 ### 1. 分代思想 ```java public class GenerationalDemo { public static void main(String[] args) { // 新生代对象 for (int i = 0; i < 100; i++) { createShortLivedObject(); } // 老年代对象 List<Object> longLived = new ArrayList<>(); for (int i = 0; i < 10; i++) { longLived.add(new byte[1024 * 1024]); // 1MB } } private static void createShortLivedObject() { byte[] temp = new byte[1024]; // 1KB // 方法结束后,对象成为垃圾 } } ``` 分代策略: 1. 新生代 - 对象朝生夕死 - 使用复制算法 - Eden和Survivor区 2. 老年代 - 对象存活率高 - 使用标记-整理算法 - 完整的垃圾回收 ## G1收集器 ### 1. G1特点 ```java public class G1Demo { public static void main(String[] args) { // 配置G1收集器 // -XX:+UseG1GC // -XX:MaxGCPauseMillis=200 // 模拟混合垃圾回收 List<byte[]> list = new ArrayList<>(); while (true) { list.add(new byte[1024 * 1024]); // 1MB if (list.size() > 100) { list.subList(0, 50).clear(); System.gc(); } } } } ``` G1的优势: 1. 并行与并发 2. 分代收集 3. 空间整合 4. 可预测的停顿 ### 2. 回收过程 ```java public class G1ProcessDemo { public static void main(String[] args) { // G1垃圾回收过程 // 1. 初始标记(STW) // 2. 并发标记 // 3. 最终标记(STW) // 4. 筛选回收 // 模拟内存分配 for (int i = 0; i < 1000; i++) { byte[] array = new byte[1024 * 1024]; // 1MB // 进行一些操作 } } } ``` 回收步骤: 1. 初始标记 2. 并发标记 3. 最终标记 4. 筛选回收 ## 实践调优 ### 1. GC参数设置 ```java public class GCTuningDemo { public static void main(String[] args) { // GC参数示例 // -XX:NewRatio=2 // -XX:SurvivorRatio=8 // -XX:MaxTenuringThreshold=15 Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); System.out.println("最大内存: " + maxMemory / 1024 / 1024 + "MB"); System.out.println("总内存: " + totalMemory / 1024 / 1024 + "MB"); } } ``` 常用参数: - -Xms:初始堆大小 - -Xmx:最大堆大小 - -XX:NewRatio:新生代和老年代的比例 - -XX:SurvivorRatio:Eden区和Survivor区的比例 ### 2. GC日志分析 ```java public class GCLogDemo { public static void main(String[] args) { // 启用GC日志 // -XX:+PrintGCDetails // -XX:+PrintGCDateStamps // -Xloggc:gc.log List<byte[]> list = new ArrayList<>(); while (true) { list.add(new byte[1024 * 1024]); // 1MB if (list.size() > 100) { list.subList(0, 50).clear(); System.gc(); } } } } ``` 日志分析要点: 1. GC发生的时间和原因 2. 各代内存使用情况 3. GC暂停时间 4. 内存分配失败情况 ## 总结 通过本文,我们详细了解了Java垃圾回收的核心算法: 1. 基础算法 - 标记-清除算法 - 复制算法 - 标记-整理算法 2. 高级算法 - 分代收集算法 - G1收集器 3. 实践应用 - GC参数调优 - 日志分析方法 在实际开发中,我们需要: 1. 理解各种GC算法的特点 2. 选择合适的垃圾收集器 3. 进行适当的GC调优 4. 监控GC的运行状况 掌握这些知识对于开发高性能Java应用至关重要。