本文参考了:
http://blog.csdn.net/androidstar_cn/article/details/54710652
http://blog.csdn.net/qq_32347977/article/details/51655521
Reference是java中的引用类,它用来给普通对像进行包装,从而在JVM在GC时,按照引用类型的不同,在回收时采用不同的逻辑。先来看下这个类的继承体系:
image.png
在进行对这些子类进行分析解释之前,我们先来看几个概念:
对象的生命周期
image.png1.创建阶段(Created)
在创建阶段系统通过下面的几个步骤来完成对象的创建过程
- 为对象分配存储空间
- 开始构造对象
- 从超类到子类对static成员进行初始化
- 超类成员变量按顺序初始化,递归条用超类的构造方法
- 子类成员变量按顺序初始化,子类构造方法调用
一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段。下面通过具体示例看看:
public class GrandParent {
public GrandParent(){
super();
System.out.println("GrandParent 构造函数");
}
{
System.out.println("GrandParent 成员代码块");
}
static {
System.out.println("GrandParent 静态代码块");
}
}
public class Parent extends GrandParent {
public Parent() {
super();
System.out.println("Parent 构造函数");
}
{
System.out.println("Parent 成员代码块");
}
static {
System.out.println("Parent 静态代码块");
}
}
public class Child extends Parent {
public Child() {
super();
System.out.println("Child 构造函数");
}
{
System.out.println("Child 成员代码块");
}
static {
System.out.println("Child 静态代码块");
}
}
child为子类,parent为child的超类,GrandParent为超类的超类,当我们执行
Child child = new Child();
执行顺序为:
image.png
当我们执行
Parent parent = new Parent();
执行顺序为:
image.png
从而证明了一个对象创建阶段的执行顺序。
2.应用阶段(In Use)
对象至少被一个强引用持有着。即上述例子中的child持有new Child()的强引用。
3.不可见阶段(Invisible)
则在此时称之为count处于不可视阶段。当然这种情况编译器在编译的过程中会直接报错了。
4.不可达阶段(Unreachable)
对象处于不可达阶段是指该对象不再被任何强引用所持有。与"不可见阶段"相比,"不可达阶段"是指程序不再持有该对象的任何强引用,这种情况下,该对象仍可能被JVM等系统下的某些已装载的静态变量或线程或JNI等强引用持有着,这些特殊的强引用被称为"GC root"。存在着这些GC root会导致对象的内存泄露情况,无法被回收。
5.收集阶段(Collected)
当垃圾回收器发现该对象已经处于"不可达阶段"并且垃圾回收起已经对该对象的内存空间重新分配做好准备时,则对象进入了"收集阶段"。如果该对象已经重写了finalize()方法,则会去执行该方法的终端操作。这里要注意尽量不要重载finalize()方法,原因有两点:
- 会影响JVM的对象分配于回收速度
在分配该对象时,JVM需要在垃圾回收器上注册该对象,以便在回收时能够执行该重载方法;在该方法执行时需要消耗CPU时间且在执行完该方法后才会重新执行回收操作,即至少需要垃圾回收器对该对象执行两次GC。 - 可能造成该对象的再次"复活"
在finalize()方法中,如果有其它的强引用再次持有该对象。则会导致对象的状态由" 收集阶段"又重新变为"应用阶段"。这个已经破坏了Java对象的生命周期进程,且复活的对象不利于后续代码管理。 - 终结阶段(Finished)
当对象执行完finalize()方法后处于不可达状态时,则该对象进入终结状态。在该阶段是等待垃圾回收器对该对象空间进行回收。 - 对象空间重分配阶段(De-allocated)
垃圾回收器对该对象的所占用的内存空间进行回收或者再分配,则该对象测底消失了,称之为"对象空重新分配阶段"
对象可达性判断
jvm 发生gc时,判断一个对象是否存在引用,都是从根结合引用开始去标识,往往到达一个对象的引用路径会很多,如下图:
image.png
那么垃圾回收时会依据两个原则来判断对象的可达性:
单一路径中,以最弱的引用为准
多路径中,以最强的引用为准
例如Obj4的引用,存在:1>6、2>5、3>4,那么从根对象到Obj4的最强引用为2>5,因为它们都是强引用。如果仅仅村子一个路径对Obj4有引用时,比如Obj4有引用时,比如现在只剩下1>6,那么根对象到Obj4的引用以最弱的为准。是软引用。Obj4就是softly-reachable对象。
强引用(StrongReference)
强引用就是我们平时创建对象,创建数组时的引用。强引用在任何时候都不会被GC回收掉。例如
Parent parent = new Parent();
软引用(SoftReference)
软引用是在系统发生OOM之前才被JVM回收掉。软引用常被用来对于内存敏感的缓存。
弱引用(WeakReference)
一旦JVM执行GC,弱引用就会被回收掉。
(虚引用)PhantomReference
虚引用主要作为其指向referent被回收时的一种通知机制。
总结
通过对SoftReference,WeakReference,PhantomReference,可以看出JDK提供这些类型的reference 主要是用来和GC交互的,根据reference的不同,让JVM采用不同策略来进行对对象的回收(reclaim)。softly-reachable的referent在保证在OutOfMemoryError之前回收对象,weakly-reachable的referent在发生GC时就会被回收,。
网友评论