java对象的生命周期包括几个阶段(并不是绝对的,有些对象并没有不可见这一过程):
- 创建阶段(Created) --构造创建初始化
- 应用阶段(In Use) --有变量引用
- 不可见阶段(invisible ---仅仅出了作用域
- 不可达阶段(Unreachable) --引用数为0 回收
- 收集阶段(Collected) --gc标记
- 终结阶段(Finalized) --调用finalize对对象进行销毁
- 对象空间重新分配阶段(De-allocated) --- 重新分配
1. 创建阶段
- 为对象分配储存空间 (堆区)
- 开始构造对象
- 从超类到子类对static成员进行初始化(类初次加载的时候才有)
- 超类成员变量按照顺序初始化,递归调用超类的构造方法
- 子类成员变脸按照顺序初始化,子类构造方法调用
一旦对象被创建 并被分派给某些变量赋值或者置于容器中,这个对象的状态就切换到了应用阶段
//构造方法
public A(){
System.out.println(" A init");
}
复制代码
对象创建方式有多种:
-
用new语句创建对象,这是最常见的创建对象的方法。
-
通过工厂方法返回对象,如:String str = String.valueOf(23);
-
运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。如:Object obj = Class.forName("java.lang.Object").newInstance();
-
调用对象的clone()方法。
-
通过I/O流(包括反序列化),如运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
2. 应用阶段
对象至少被一个强引用持有着(包括被数组 和Java容器引用),正常使用且在作用域内。和创建阶段最主要的区别在于有没有引用指向它
A a = new A(); // a指向 所以属于应用阶段
List list = new ArrayList();
list.add(a); // 数组内会保存对象的引用 属于应用阶段
new A(); // 无强引用 创建即为不可达阶段
复制代码
3. 不可见阶段(invisible)
本质上来说就是已经过了作用域,但由于未对对象的引用进行手动指向null或者其他对象,所以会导致对象状态处于这种不可见状态,就是实质有变量引用,引用存在,但是使用区域超出作用域,如下面代码段所示,在输出i时已经过了i的作用域(这里在编译期就会报错),在这个时候其实已经不持有i变量引用,所以该对象属于不可见阶段。
if(true) {
int i = 1;
}
System.out.println(i);
复制代码
4. 不可达阶段(Unreachable)
对象处于不可达阶段是指对象不被任何强引用持有,即引用计数为0.
A a = new A(); //新建一个对象 并有一个强引用 a指向它 引用计数为1
a =null; // a指向null,原有对象不再被强引用引用,所以对象变为不可达状态。(下次gc时会被回收)
//除此之外强引用还有 数组之类的容器
B b = new B(); //引用计数为1
List list = new ArrayList();
list.add(b); //引用计数 加1 计数器为2
b = null;// 引用计数减1 这个时候引用计数为1 之前new出来的B的那个对象并不符合垃圾回收机制的规则,因为他被list持有。
list.remove(); //这个时候 list不再持有该对象, 引用计数减1 ,对象为不可达阶段,符合垃圾回收规则,将会在下一次gc被释放
复制代码
5. 收集阶段
对象标记为不可用时进入收集阶段,即垃圾回收器发现该对象为不可用。此时会调用finalize()。
注意:不要重载finalize方法,主要原因有亮点
- 可能导致对象重新进入应用阶段,导致内存泄漏。在finalize方法中,如果对该对象新增其他强引用(引用指向,或者放入数组之类的容器),导致对象重新进入应用阶段,这种对象完全不利于后续的代码管理,无法对空间进行释放
- 在分配该对象时,JVM需要在垃圾回收器上注册该对象,以便在回收时能够执行该重载方法;在该方法的执行时需要消耗CPU时间且在执行完该方法后才会重新执行回收操作,即至少需要垃圾回收器对该对象执行两次GC。
6.终结阶段
执行完 finalize方法,如果还是不可达状态 等待GC执行垃圾回收
7.对象空间再分配阶段(deallocated)
Deallocated状态是垃圾回收的最后一步,如果经过上面所有的阶段对象仍为unreachable,就可以进入deallocation阶段了。当然何时回收、再分配及相关算法取决于JVM虚拟机本身。