看了很多的reference object相关文章,有些地方写得欠妥,不全,容易误导!
我来说说自己的看法:
1. 理论前提:对象的生命周期:
new --> reachable --> unreachable --> finalizable --> finalized --> reclaimed
2. weak reference:
检测到weak reachable后,jvm同时会干这么几件事:
1)擦除referent字段,(当然还有链上上其他referent字段)
2)referent原指向对象状态置为finalizable
3)之后会装入队列。
从中可以看出:
1)从队列里取出reference后,get()方法返回referent值,为null。
2)referent原指向对象的finalize()方法异步被调用(Finalizer线程)。
3)如果finalize()方法恶心的发布了强引用的this,不影响到队列相关的装入取出!
3. phantom reference:
满足两个条件才会被装入队列:
1)referent指向对象是finalized状态(要不然就进入reclaimed即物理释放了)。
2)phantom可达条件满足。
设计要领:
1)为了确保referent指向的对象可以被物理释放,get()方法重写为放回null。就是防止取回作为强引用!
2)referent指向对象不会被collector清除,除非references cleared。
从中可以看出:
1)队列中有reference后,指向对象的finalize()已经被调用,就差物理释放了。
2)references清除后,指向对象就可以物理释放了。
3)如果finalize()方法发布了this,是什么结果?对象又变成reachable了,不会被加入到队列中。这样就解决了恶心的finalize问题。
4)phantom目的很明显,应用代码可以依此追踪对象的生命周期-->finalized。
4. 假设我们需要跟踪对象a的生命周期,好做资源释放。
1)什么时候才是最佳的释放时机,a进入到unreachable或者finalized状态中?
2)如何监听这个状态?weak只有finalize()方法被调用(被动得知),或者轮训队列(主动得知)。phantom有个子类cleaner,可以在如队列之前,调用钩子(主动得知)。
3)为什么finalize不好?jvm规范没有规定finalizable-->finalize的具体时间,有可能很长。
我来说说自己的看法:
1. 理论前提:对象的生命周期:
new --> reachable --> unreachable --> finalizable --> finalized --> reclaimed
2. weak reference:
检测到weak reachable后,jvm同时会干这么几件事:
1)擦除referent字段,(当然还有链上上其他referent字段)
2)referent原指向对象状态置为finalizable
3)之后会装入队列。
从中可以看出:
1)从队列里取出reference后,get()方法返回referent值,为null。
2)referent原指向对象的finalize()方法异步被调用(Finalizer线程)。
3)如果finalize()方法恶心的发布了强引用的this,不影响到队列相关的装入取出!
3. phantom reference:
满足两个条件才会被装入队列:
1)referent指向对象是finalized状态(要不然就进入reclaimed即物理释放了)。
2)phantom可达条件满足。
设计要领:
1)为了确保referent指向的对象可以被物理释放,get()方法重写为放回null。就是防止取回作为强引用!
2)referent指向对象不会被collector清除,除非references cleared。
从中可以看出:
1)队列中有reference后,指向对象的finalize()已经被调用,就差物理释放了。
2)references清除后,指向对象就可以物理释放了。
3)如果finalize()方法发布了this,是什么结果?对象又变成reachable了,不会被加入到队列中。这样就解决了恶心的finalize问题。
4)phantom目的很明显,应用代码可以依此追踪对象的生命周期-->finalized。
4. 假设我们需要跟踪对象a的生命周期,好做资源释放。
1)什么时候才是最佳的释放时机,a进入到unreachable或者finalized状态中?
2)如何监听这个状态?weak只有finalize()方法被调用(被动得知),或者轮训队列(主动得知)。phantom有个子类cleaner,可以在如队列之前,调用钩子(主动得知)。
3)为什么finalize不好?jvm规范没有规定finalizable-->finalize的具体时间,有可能很长。
4)phantom如队列之前,finalize会被调用,而且时间不定,可能很长,那这个方法好吗?jvm特殊对待重载finalize的对象,会调度到finialzer线程处理(较慢的方式)。所以,建议用phantom方式释放资源,finalize最好不要重载。示例代码参考DirectBuffer。
给份代码,哈哈,自己设计的:
package com.eastsoft.sample.java;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
/**
* Created by MQ. EL on 2014/7/18.
*/
public abstract class JavaMain {
public static MQ m;
public static void main(String[] args) {
MQ mq = new MQ();
ReferenceQueue<MQ> rq = new ReferenceQueue();
PhantomReference<MQ> pr = new PhantomReference<MQ>(mq, rq);
// WeakReference<MQ> pr = new WeakReference<MQ>(mq, rq);
System.out.println(mq);
while (true) {
mq = null;
m = null;
try {
System.gc();
Thread.sleep(1000);
Reference<MQ> p = (Reference<MQ>) rq.poll();
if (p != null) {
System.out.println(p);
Class<Reference> cl = Reference.class;
Field field = cl.getDeclaredField("referent");// cl.getField("referent");
field.setAccessible(true);
Object obj = field.get(p);
System.out.println(((MQ) obj).i);
MQ qq = (MQ) obj;
qq.i = 2;
m = qq;
pr = new PhantomReference<MQ>(qq, rq);
System.out.println(qq);
} else
System.out.println("null");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class MQ {
public int i = 1;
@Override
public String toString() {
return super.toString() + "MQ";
}
@Override
public void finalize() {
System.out.println("finish");
// JavaMain.m = this;
}
}
可以猜猜结果哦!超出你的想象,和其他的blog都说的不一样!
结论倒是很简单,只要对象没有物理释放,生命周期都可以转换。
对了针对referent这个变量,不是强引用,gc是特殊对待的一种引用!
1199

被折叠的 条评论
为什么被折叠?



