Java对象生命周期
在jvm运行空间中,对象的整个生命周期大致可以分为七个阶段:
- 创建阶段(Creation)
- 应用阶段(USing)
- 不可视阶段(Invisible)
- 不可到达阶段(Unreachable)
- 可收集阶段(Collected)
- 终结阶段(Finalized)
- 释放阶段(Free)
一、创建阶段
在对象创建阶段,系统要通过下面步骤,完成对象的创建过程:
- 为对象分配存储空间
- 开始构造对象
- 递归调用其超类的构造方法
- 进行对象实例初始化和变量初始化
- 执行构造方法体
第3步是指递归地调用该类所扩展的所有父类的构造方法,一个Java类(除了Object类)至少有一个父类(Object),这个规则既是强制的,也是隐式的
在创建对象时,我们应该遵循一些规则,以提高应用的性能。下面是创建对象时的几个关键应用规则:
- 避免在循环体中创建对象,即使该对象占用内存空间不大
- 尽量及时使对象符合垃圾回收标准
- 不要采用过深的继承层次
- 访问本地变量优于访问类变量
1 2 3 4 5 6 7 8 9 10 | for ( int i = 0 ; i < 10000 ; ++i) { Object obj = new Object(); System.out.println( "obj= " + obj); } //正确写法 Object obj = null ; for ( int i = 0 ; i < 10000 ; ++i) { obj = new Object(); System.out.println( "obj= " + obj); } |
二、应用阶段
在对象的应用阶段,对象具备下列特征:
- 系统至少维护着对象的一个强引用(Strong Reference)
- 所有对该对象的引用都是强引用(除非我们显示地使用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference))
对象引用的层次结构:
1、强引用:指jvm内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就称为强引用。
2、软引用:软引用的主要特点是具有较强的引用功能,只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。另外,这些引用对象还能保证在Java抛出OutOfMemory异常之前,被设置为null。它可以用于实现一些常用资源的缓存,实现Cache缓存功能,保证最大程度地使用内存而不引起OutOfMemory。软可到达对象的所有软引用都要保证在虚拟机抛出OutOfMemory之前已经被清除,否则,清除软引用的时间或者清除不同对象的一组此类引用的顺序将不受任何约束。然而,虚拟机实现不鼓励清除最近访问或使用过的软引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import java.lang.ref.SoftReference; A a = new A(); … // 使用 a … // 使用完了a,将它设置为soft 引用类型,并且释放强引用; SoftReference sr = new SoftReference(a); a = null ; … // 下次使用时 if (sr!= null ) { a = sr.get(); } else { // GC由于内存资源不足,可能系统已回收了a的软引用, // 因此需要重新装载。 a = new A(); sr= new SoftReference(a); } |
软引用技术的引进,使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃(crash)。因此在处理一些占用内存较大而且声明周期较长,但使用并不频繁的对象时应尽量应用该技术。正像上面的代码一样,我们可以在对象被回收之后重新创建(这里是指那些没有保留运行过程中状态的对象),提高应用对内存的使用效率,提高系统稳定性。但事物总是带有两面性的,有利亦有弊。在某些时候对软引用的使用会降低应用的运行效率与性能,例如:应用软引用的对象的初始化过程较为耗时,或者对象的状态在程序的运行过程中发生了变化,都会给重新创建对象与初始化对象带来不同程度的麻烦,有些时候我们要权衡利弊择时应用。
3、弱引用:弱引用对象与软引用对象的最大不同在于:GC在进行回收时,需要通过算法检查是否回收软引用对象,而对于弱引用对象,GC总是进行回收。虽然GC在运行时肯定回收软弱引用对象,但关系复杂的弱引用对象群常常需要好几次GC的运行才能完成回收。弱引用对象常常用于Map数据结构中,引用占用内存空间较大的的对象,一旦该对象的强引用为null时,对这个对象的引用就不存在了,GC能够快速地回收该对象空间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import java.lang.ref.WeakReference; A a = new A(); … // 使用 a … // 使用完了a,将它设置为weak 引用类型,并且释放强引用; WeakReference wr = new WeakReference (a); a = null ; … // 下次使用时 if (wr!= null ) { a = wr.get(); } else { a = new A(); wr = new WeakReference (a); } |
弱引用技术主要适用于实现无法防止其键(或值)被回收的规范化映射。另外,弱引用分为“短弱引用(Short Week Reference)”和“长弱引用(Long Week Reference)”,其区别是长弱引用在对象的Finalize方法被GC调用后依然追踪对象。基于安全考虑,不推荐使用长弱引用。因此建议使用下面的方式创建对象的弱引用。
1 2 3 | WeakReference wr = new WeakReference(obj); //或 WeakReference wr = new WeakReference(obj, false ); |
4、虚引用:
虚引用(Phantom Reference)的用途较少,主要用于辅助finalize函数的使用。Phantom对象指一些执行完了finalize函数,并且为不可达对象,但是还没有被GC回收的对象。这种对象可以辅助finalize进行一些后期的回收工作,我们通过覆盖Reference的clear()方法,增强资源回收机制的灵活性。虚引用主要适用于以某种比 java 终结机制更灵活的方式调度 pre-mortem 清除操作。
注意:在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。
三、不可视阶段
在一个对象经历了应用阶段后,那么该对象便处于不可视阶段,说明我们在其他区域的代码中已经不可以再引用它,其强引用已经消失。例如,本地变量超出了其可视范围,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public void process () { try { Object obj = new Object(); obj.doSomething(); } catch (Exception e) { e.printStackTrace(); } while (isLoop) { // ... loops forever // 这个区域对于obj对象来说已经是不可视的了 // 因此下面的代码在编译时会引发错误 obj.doSomething(); } } |
如果一个对象已使用完,而且在其可视区域不再使用,此时应该主动将其设置为空(null)。可以在上面的代码行obj.doSomething();下添加代码行obj = null;,这样一行代码强制将obj对象置为空值。这样做的意义是,可以帮助JVM及时地发现这个垃圾对象,并且可以及时地回收该对象所占用的系统资源。
四、不可到达阶段
处于不可到达阶段的对象,在虚拟机所管理的对象引用根集合中再也找不到直接或间接的强引用,这些对象通常是指所有线程栈中的临时变量,所有已装载的类的静态变量或者对本地代码接口(JNI)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。其实所有垃圾回收算法所面临的问题是相同的——找出由分配器分配的,但是用户程序不可到达的内存块。
五、可收集阶段、终结阶段与释放阶段
当对象处于这个阶段的时候,可能处于下面三种情况:
(1)垃圾回收器发现该对象已经不可到达。
(2)finalize方法已经被执行。
(3)对象空间已被重用。
当对象处于上面的三种情况时,该对象就处于可收集阶段、终结阶段与释放阶段了。虚拟机就可以直接将该对象回收了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术