Java中针对finalize的实现和相应的执行过程
作者:ImportNew 发布时间:[ 2016/9/23 11:17:09 ] 推荐标签:测试开发技术 Java
FinalReference引用
此类是一个package类型,表示它并不是公开的一部分,继承自Reference, 即表示也是一种特定的引用类型,因此每个包装在其中的对象在被回收之前,自己都会放到指定的referqyebceQueue当中.
这个引用对象专门为带finalize方法的类服务,可以理解为每一个有相应的方法的对象,其都会封装为一种finalRefernece对象.
因为finalize方法是object定义的,其默认实现为空.那么如果重写了此方法,那么方法体肯定不为空.即可以通过这一种区别来.只要finalize方法实现不为空的类,此产生的对象都需要被注册到finalRefernece中.
这一步可以通过在newInstance的时候,即调用object默认构造方法的时候,可以进行相应的注册了.
Finalizer#register方法
主要调用了此方法,会产生相应的finalizer对象,而finalizer对象是继承于finalReference的.此方法声明如下:
/* Invoked by VM */
static void register(Object finalizee) {
new Finalizer(finalizee);
}
从上面注释可以看出,此方法会被jvm在特定时期调用.
然后切换到Finalizer的构造方法,如下所示:
private Finalizer(Object finalizee) {
super(finalizee, queue);
add();
}
可以看出,相应的引用对象会通过queue进行回调.add的作用在于将所有还未进行finalize方法的对象存起来,在后System.shutdown时调用.通过Runtime#runFinalizersOnExit进行设置.
ReferenceQueue
此引用队列会在相应reference对象的内部对象被回收之前放到此队列中(详细说明在另一篇关于reference中再说明.),因为只需要从此队列中拿到相应的对象,那么此对象肯定是准备被回收的.
那么在回收之前调用相应的finalize方法即可.
FinalizerThread线程
此线程即是从queue里面,不停的获取数据,然后调用相应的finalize方法.相应的代码如下所示:
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
f.runFinalizer(jla);
} catch (InterruptedException x) {
// ignore and continue
}
}
而相应的runFinalizer如下所示:
synchronized (this) {
if (hasBeenFinalized()) return;
remove();
}
try {
Object finalizee = this.get();
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
jla.invokeFinalize(finalizee);
/* Clear stack slot containing this variable, to decrease
the chances of false retention with a conservative GC */
finalizee = null;
}
} catch (Throwable x) { }
super.clear();
在上面的逻辑当中,首先调用remove将其从未finalize中移除.这个方法是保证每个对象的finalize多只会被调用一次,即当前这次调用完了.它会被记相应的状态,即hasBeenFinalized返回为true(其实是把里面的next指针指向自己.即自己从未finalize中移除,同时也不需要再次调用finalize了).
接下来是调用相应的finalize方法,上面的jla.invokeFinalize其实是调用相应对象的finalize方法. 在这个处理中,首先通过get获取原始对象.在整个jvm处理中,针对finalizeReference在回收之前默认是不将引用设置为null.因为这里,总是能够获取相应的引用对象.
处理完之后,后调用相应的clear,清除相应的引用.这样达到终引用没有其它对象可引用的效果.
在上面的处理当中,并没有限定调用finalize的时间.因此,一旦如果某个对象的finalize调用慢,会影响到整个回收链的执行,这下会产生相应的OOM异常了.因此,除非特殊情况,不要重写finalize,相应的场景都应该有其它方法可以处理.比如guava中的FinalizableReference.
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11