java对象的生命周期由以下几个部分组成
1).创建阶段(Created)
2).应用阶段(In Use)
3).不可见阶段(Invisible)
4).不可达阶段(Unreachable)
5).收集阶段(Collected)
6).终结阶段(Finalized)
7).对象空间重分配阶段(De-allocated)
创建阶段
通过以下的几个步骤来完成对象的创建过程
1).为对象分配存储空间;
2).开始构造对象;
3).从超类到子类对static成员进行初始化;
4).超类成员变量按顺序初始化,递归调用超类的构造方法;
5).子类成员变量按顺序初始化,子类构造方法调用;
一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段
一个Java类(除Object类外)至少有一个父类(Object),这个规则既是强制的,也是隐式的。你可能已经注意到在创建一个Java类的时候,并没有显式地声明扩展(extends)一个Object父类
public class A {
…
}
这个声明等同于下面的声明:
public class A extends java.lang.Object {
…
}
创建对象时应该遵循的规则
避免在循环体中创建对象,即使该对象占用内存空间不大。
… …
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);
}
… …
这种写法,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象应用,浪费大量的内存空间,而且增大了系统做垃圾回收的负荷。
不要对一个对象进行多次初始化,这同样会带来较大的内存开销,降低系统性能。
应用阶段
对象至少被一个强引用持有称为处于应用阶段,一个对象可以有多个强引用,GC不会回收处于应用状态的对象
强引用
强引用(Strong Reference)是指JVM内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用。
软引用
软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。
… …
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);
}
弱引用
GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象, GC总是进行回收。因此Weak引用对象会更容易、更快被GC回收。
… …
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);
}
… …
虚引用
虚引用(Phantom Reference)的用途较少,主要用于辅助finalize函数的使用。Phantom对象指一些执行完了finalize函数,并且为不可达对象,但是还没有被GC回收的对象。
不可视阶段
当一个对象处于不可见阶段时,说明程序本身不再持有该对象的不论什么强引用,尽管该这些引用仍然是存在着的。
可以理解为程序的运行已经超出了该对象的作用域了。
… …
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)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。其实所有垃圾回收算法所面临的问题是相同的——找出由分配器分配的,但是用户程序不可到达的内存块。
收集阶段(Collected)
当垃圾回收器发现该对象已经处于“不可达阶段”而且垃圾回收器已经对该对象的内存空间又一次分配做好准备时,则对象进入了“收集阶段”。假设该对象已经重写了finalize()方法,则会去运行该方法的终端操作。
非特殊不要重载finazlie()方法,原因有两点:
1). 会影响JVM的对象分配与回收速度,在分配该对象时,JVM须要在垃圾回收器上注冊该对象,以便在回收时可以运行该重载方法;在该方法的运行时须要消耗CPU时间且在运行完该方法后才会又一次运行回收操作,即至少须要垃圾回收器对该对象运行两次GC。
2).可能造成该对象的再次“复活”,在finalize()方法中,假设有其他的强引用再次持有该对象,则会导致对象的状态由“收集阶段”又又一次变为“应用阶段”。这个已经破坏了Java对象的生命周期进程,且“复活”的对象不利用代码管理。
终结阶段(Finalized)
当对象运行完finalize()方法后仍然处于不可达状态时,则该对象进入终结阶段。在该阶段是等待垃圾回收器对该对象空间进行回收。
对象空间重分配阶段(De-allocated)
垃圾回收器对该对象的所占用的内存空间进行回收或者再分配了,则该对象彻底消失了,称之为“对象空间又一次分配阶段”