网站首页 > 文章精选 正文
Java对象生命周期全解析:从类加载到GC回收的完整旅程
一、对象诞生阶段(加载与初始化)
Ⅰ 类加载机制
当程序首次访问某个类时,JVM通过多级加载器完成类信息的加载与验证:
public class Person {
// 类首次使用时触发加载流程
static {
System.out.println("Person类初始化完成");
// 类初始化阶段执行静态代码块:ml-citation{ref="7" data="citationList"}
}
}
加载过程:
- 加载(Loading) :通过BootStrapClassLoader→ExtClassLoader→AppClassLoader三级委派机制加载.class文件47
- 验证(Verification) :检查字节码格式防止恶意代码注入(如修改魔数0xCAFEBABE)
- 准备(Preparation) :为静态变量分配内存并赋默认值(如int→0,对象→null)17
- 解析(Resolution) :常量池符号引用转为直接引用
- 初始化(Initialization) :执行<clinit>方法完成静态变量赋值7
Ⅱ 对象实例化
Person p = new Person();
// 真实内存操作步骤:
// 1. 指针碰撞或空闲列表方式堆内存分配(堆内存连续时优先指针碰撞):ml-citation{ref="5,8" data="citationList"}
// 2. 内存空间初始化为零值(int age→0,String name→null)
// 3. 设置对象头(MarkWord+类元指针)
// 4. 执行构造函数<init>进行赋值:ml-citation{ref="7" data="citationList"}
内存分配策略:
- 新对象优先进入Eden区:默认占堆内存1/3空间18
- TLAB优化:通过-XX:+UseTLAB开启线程私有分配缓冲区,减少内存竞争7
二、对象存活阶段(堆内存迁移)
Ⅰ 新生代存活周期
public class SurvivorDemo {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
for(int i=0; i<100; i++) {
// 每次分配1MB内存触发Minor GC
byte[] data = new byte[1024*1024];
list.add(data);
// 第3次循环时Survivor区满,触发晋升
if(i == 2) list.clear();
}
}
}
迁移过程:
- Eden区分配:新对象99%在此分配(例外:大对象直接进老年代)
- Minor GC触发:Eden满时启动复制算法,存活对象转移到Survivor区
- 年龄计数器:每次GC后对象年龄+1(最大值15,可通过-XX:MaxTenuringThreshold调整)15
- 晋升条件:
- 年龄超过阈值
- Survivor区同年龄对象总大小超过其空间50%
- 分配担保失败(老年代剩余空间不足新生代对象总大小)58
Ⅱ 老年代生命周期
// 长期存活对象示例:缓存系统
public class CacheSystem {
private static Map<String,Object> cache = new HashMap<>();
public static void cacheData(String key, Object value) {
cache.put(key, value); // 缓存长期持有引用
}
public static void clearCache(String key) {
cache.remove(key); // 显式移除引用才能被回收
}
}
老年代特点:
- 存放长期存活对象(如Spring单例Bean)
- 采用标记-清除或标记-整理算法(CMS/G1可并发处理)56
- Full GC触发条件:
- 老年代空间不足
- 永久代/元空间不足(JDK8+)
- System.gc()显式调用(不推荐)8
三、对象终结阶段(GC回收)
Ⅰ 回收判定算法
// 可达性分析示例
public class GCRootsDemo {
Object instance;
public static void main(String[] args) {
GCRootsDemo a = new GCRootsDemo();
GCRootsDemo b = new GCRootsDemo();
a.instance = b; // 循环引用
b.instance = a;
a = null; // 切断GC Roots
b = null;
System.gc(); // 循环引用仍会被回收
}
}
回收判定机制:
- 可达性分析:从GC Roots(栈引用、静态变量等)出发遍历引用链
- 两次标记流程:
- 第一次标记不可达对象
- 执行finalize()方法后二次标记(对象复活唯一机会)6
Ⅱ 回收执行过程
public class FinalizeDemo {
static FinalizeDemo hook;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("执行finalize方法");
hook = this; // 对象复活
}
public static void main(String[] args) throws Exception {
hook = new FinalizeDemo();
hook = null;
System.gc();
Thread.sleep(500);
System.out.println(hook != null ? "对象存活" : "对象被回收");
}
}
终结阶段流程:
- 不可见阶段:超出作用域但仍有潜在引用(如线程局部变量)
- 不可达阶段:无任何GC Roots可达
- 收集阶段:被GC标记为待回收对象
- 终结阶段:执行finalize()方法(不保证及时性)
- 内存释放:对象空间被重新分配给其他对象68
四、实战优化策略
Ⅰ 内存泄漏检测
// 典型内存泄漏场景:未关闭的资源
public class ResourceLeak {
public static void main(String[] args) {
List<Connection> connections = new ArrayList<>();
while(true) {
Connection conn = DriverManager.getConnection(DB_URL);
connections.add(conn); // 未关闭的连接持续堆积
// 正确做法:使用try-with-resources自动关闭
}
}
}
检测工具:
- jmap:生成堆转储文件
- VisualVM:实时监控堆内存变化
- Eclipse MAT:分析内存泄漏根源46
Ⅱ GC调优参数
参数 | 作用描述 | 适用场景 |
-Xms2048m | 初始堆大小 | 避免堆动态调整开销 |
-Xmx2048m | 最大堆大小 | 防止OOM |
-XX:+UseG1GC | 启用G1收集器 | 大内存低延迟场景 |
-XX:MaxGCPauseMillis=200 | 最大GC停顿时间目标 | 响应敏感型系统 |
-XX:SurvivorRatio=8 | Eden与Survivor区占比 | 调整新生代对象存活时间 |
猜你喜欢
- 2025-07-23 JVM中哪些是线程共享区,哪些是线程独占区
- 2025-07-23 线上服务 FGC 问题排查,看这篇就够了
- 2025-07-23 JVM运行时内存区域、堆内存分段机制
- 2025-07-23 JVM运行数据区深度解析(jvm运行时区域)
- 2025-07-23 开发者必备!线上内存泄漏排查的 8 个 Linux 实战工具
- 2025-07-23 内存溢出满分排查步骤,看完不用担心拿不到Offer了
- 2025-07-23 关于JVM调优,看这篇就够了(jvm调优实战简书)
- 2025-07-23 那么大个对象的垃圾回收有什么不同
- 2025-07-23 GC分代年龄为什么是15?(对象gc的分代年龄保存在)
- 2025-07-23 JVM参数调优,一文让你搞懂,再也不为应用操心了!
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)
- fmt.println (52)