【问题标题】:Messing with java finalize()搞砸 java finalize()
【发布时间】:2013-11-18 05:29:54
【问题描述】:

我读到 JVM gc 在找到一个无法访问的对象后,运行该对象的 finalize() 方法。然后它检查对象是否仍然无法访问,如果不是,则将其删除。所以我写了一个finalize,让它的对象引用再次可用:

public class Stuff {

 List<Object> list;

 public Stuff(List<Object> list) {
  this.list = list;
 }

 @Override
 protected void finalize() throws Throwable {
  list.add(this);
  System.out.println("A Stuff is finalized");
 }
}

主要方法如下:

public class Main { 
 public static void main(String[] args) {
  List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));
 }
}

gc 运行,因为“A stuff is finalized”出现在标准输出上,但 main 中的打印行随后抛出 IndexOutOfBoundsException。我可以完成这项工作吗?

我通常根本不使用 finalize,我只是觉得看看 finalize 是否可以使其对象的引用再次可用会很有趣。我可以做这个吗?

【问题讨论】:

标签: java reference finalize


【解决方案1】:

终结器在专用终结器线程中运行,而您编写的是线程不安全的代码。例如,使用同步集合。

另一个陷阱是,仅调用System.gc() 并不能保证在方法调用返回时终结器已经运行。终结器只是在终结器线程的队列中排队——即使这样。要解决这个问题,您应该真正使用同步助手,例如 CountDownLatch 并调用 System.gc() 两到三遍,以获得良好的效果。

在这里,您的代码根据上述想法进行了改进:

public class Stuff {

  static final List<Stuff> list = Collections.synchronizedList(new ArrayList<Stuff>());
  static final CountDownLatch cdl = new CountDownLatch(1);

  @Override protected void finalize() {
    list.add(this);
    cdl.countDown();
  }

  public static void main(String[] args) throws Exception {
    list.add(new Stuff());
    list.remove(0);
    System.gc();
    System.gc();
    cdl.await();
    System.out.println(list.size());
  }
}

【讨论】:

  • 我放了一个 Thread.sleep(500);在 gc 调用之后在 main 中。现在 gc 线程有足够的时间运行,所以它可以工作了。我想如果我需要的话我可以同步这个,现在我很满意知道 finalize 可以使参考再次可用。感谢您的快速回复。
  • 是的,我使用了代码并添加了 sleep 作为最简单的 hack,它也对我有用 :)
  • 我已经使用我公开的想法的代码编辑了答案。我必须说很高兴看到没有明显延迟的积极结果:)
【解决方案2】:
List<Object> list = new ArrayList<>();
  list.add(new Stuff(list));
  list.remove(0);
  System.gc();
  System.out.println(list.get(0));

您正在创建Object 的列表,而不是List 的Stuff 类实例列表,并实现了finalize。所以ArrayIndexOutOfBound 是预期的。

【讨论】:

  • 跟踪可终结对象的运行时不知道AraryList 实例或任何其他实例上的泛型类型参数。无论如何,这个列表是无关紧要的——一个对象要么是可访问的,要么是不可访问的。
猜你喜欢
  • 2010-09-05
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多