从Effective Java 2nd Edition第7项:避免终结器
“哦,还有一件事:使用终结器会严重影响性能。在我的机器上,创建和销毁一个简单对象的时间约为5.6 ns。添加终结器会将时间增加到2,400 ns。换句话说,使用终结器创建和销毁对象的速度要快430倍。“
如何衡量创建和销毁对象的时间? 你做的只是:
long start = System.nanoTime();
SimpleObject simpleObj = new SimpleObject();
simpleObj.finalize();
long end = System.nanoTime();
long time = end - start;
答案 0 :(得分:2)
仅测量执行finalize方法的时间。最终确定的绝大部分费用将由GC必须执行的特殊处理。
答案 1 :(得分:1)
在许多情况下,这种方法是最好的,在这种情况下,您编写的代码不是唯一涉及的代码 - 您依赖于系统调用或外部资源。
我认为这就是Joshua Bloch在这种情况下所做的,但是我的副本在楼上,我感觉很懒。
答案 2 :(得分:0)
您可以请求运行时通过Runtime.gc()
执行垃圾收集,但垃圾收集器不需要在那里执行它然后:
finalize()
方法,而是由垃圾收集器调用simpleObj
设置为null
,然后调用垃圾收集即可实现更逼真的场景答案 3 :(得分:0)
一种可能的解决方案是依赖 java.lang.ref
包,该包仅支持与垃圾收集器的有限程度的交互。
测量结果不准确,因为很难知道物体的真正结局。我相信 Joshua 必须有另一种方法来衡量时间,也许前往 JVM 本身。
PhantomReference
最接近对象生命周期结束的引用。换句话说,对象是幻影可达。
public class WithoutFinalizationV1 {
public static void main(String[] args) {
ReferenceQueue<WithoutFinalizationV1> queue = new ReferenceQueue<>();
long start = System.nanoTime();
PhantomReference<WithoutFinalizationV1> rf = new PhantomReference<>(
new WithoutFinalizationV1(), queue);
System.gc(); //advise JVM to do GC
Object x = null;
int waitCount = -1;
do{
x = queue.poll();
waitCount++;
} while(x == null);
//only need this time point
System.out.println("WithoutV1 "+ waitCount + " " + (System.nanoTime() - start));
}
}
跑了几次,世界纪录是5394860ns,远不是5.6ns。
添加后
@Override
protected void finalize() throws Throwable {
}
结果是 5632208ns。
Here 摘自我写的相关帖子。