1

来自 Effective Java 第 2 版第 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;
4

4 回答 4

2

这仅测量执行 finalize 方法的时间。最终确定的绝大部分成本将用于 GC 必须执行的特殊处理。

于 2010-04-03T14:29:03.427 回答
1

与其像 Tom Hawtin 上面所说的那样徒劳地尝试对此进行微基准测试,最好的方法是检查执行几十万个创建和销毁周期的时间,然后除以周期数。

在您编写的代码不是唯一涉及的代码的许多情况下,这种方法是最好的——您依赖于系统调用或外部资源。

我认为这就是 Joshua Bloch 在这种情况下所做的,但我的副本在楼上,我感到很懒惰。

于 2010-04-03T15:29:51.643 回答
0

您可以通过 请求运行时执行垃圾收集Runtime.gc(),但不需要垃圾收集器立即执行它,然后:

  • finalize()方法不是由您调用,而是由垃圾收集器调用
  • 您可以简单地将 设置simpleObjnull,然后调用垃圾收集来实现更真实的场景
于 2010-04-03T15:18:22.107 回答
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。

是我写的相关帖子的摘录。

于 2021-07-22T14:25:18.413 回答