【问题标题】:finalize() method not getting called despite WeakReference [duplicate]尽管 WeakReference 没有调用 finalize() 方法[重复]
【发布时间】:2016-02-28 06:33:36
【问题描述】:

我目前遇到一个问题,即我的一类对象没有调用其finalize() 方法,尽管它仅存储在ConcurrentHashMap 作为值,而对象的UUID 作为映射的键。

这是我创建的示例(它不是在我的实际项目中使用的示例,但此示例也没有调用对象的 finalize() 方法。

TestMain.class //处理HashMap的主类

public class TestMain {

public static ConcurrentHashMap<String, WeakReference<Test>> map = new ConcurrentHashMap<String, WeakReference<Test>>();

  public static void main(String args[]) {
    map.put("Key1", new WeakReference<Test>(new Test("test 1", 2))); //This "Test" Object shouldn't be accessible anywhere besides the HashMap anymore, and therefore I want it to be "finalized" by the garbage collector.
    System.out.println("DONE");
  } 
}

Test.class //对象类

public class Test {
  public String string;

  public int intt;

  public Test(String string, int intt) {
    this.string = string;
    this.intt = intt;
  }

  @Override
  protected void finalize() throws Throwable {
    System.out.println("FINALIZED TEST CLASS: " + string);
    super.finalize();
  }
}

当 main 方法运行时,打印的所有内容都是“DONE”,而我预计在此之前也会打印“FINALIZED TEST CLASS:Test 1”。我的代码有问题,还是我误解了 finalize() 的工作原理?

另外,我希望它能够像我解释的那样工作,因为我需要使用 finalize() 方法从“映射”Map 和内存中删除对象,因为在此期间将生成数百个对象我的项目的运行持续时间,因此我希望清除不再使用的对象,以便为更多新对象腾出空间。

编辑:我在互联网上的其他地方看到人们说程序可能会在垃圾收集器有机会处理上述对象之前终止。因此,我试图通过添加一个简单的while(true){} 循环来让我的程序不终止,并等待了几分钟,但仍然没有看到对象正在“完成”的消息。

非常感谢任何帮助,谢谢。

【问题讨论】:

  • 不保证finalize方法会被调用
  • @PragnaniKinnera 那么在其他任何地方都无法访问这些对象后,我将如何手动处理它们呢?我现在很困惑
  • @C_Beth 这不是你的工作,GC 会处理的。当您尝试自己做时,会引起额外的头痛

标签: java


【解决方案1】:

最可能的解释是 GC 从未运行过。

  • 如果 GC 不运行,则不会对对象进行垃圾回收。

  • 如果不收集对象,它们将不会被最终确定。

试图通过添加一个简单的 while(true){} 循环来让我的程序不终止,并等待了几分钟,

等待 GC 不会有帮助。通常它只在>>需要

您可以通过调用System.gc() 来强制GC 运行...但这是不良做法。这将使您的应用程序效率低下且无响应。

尝试在终结器中做任何必须及时完成的​​事情也是不明智的。你应该这样设计你的代码:

  • 对象是否永远不会最终确定并不重要,并且
  • 对象何时完成并不重要。

为什么?因为您几乎无法控制对象何时完成……如果您不调用 System.gc() 则根本无法控制……这是您不应该做的;见上文。

实际上,终结器是 Java 的一个特性,应该很少使用,如果有的话。唯一有效的用例涉及释放与应用程序尚未整理的资源对象相关联的外部资源。即使这样,应用程序最好使用“资源尝试”(或finally 块)来明确清理资源。

【讨论】:

  • prntscr.com/a8w7rq 添加了System.gc() 并且它确实证明了当GC被调用时它会正常工作。谢谢
【解决方案2】:

正如 cmets 中正确提到的,不能保证调用 finalize 方法。

Java 编程语言不保证哪个线程会 为任何给定对象调用 finalize 方法。可以保证, 但是,调用 finalize 的线程不会持有任何 调用 finalize 时用户可见的同步锁。如果 finalize 方法抛出未捕获的异常,异常是 被忽略并且该对象的终结终止。

现在回到您担心在这些对象不再可访问后手动处置这些对象的问题上,您无需处理这些问题,Java 垃圾收集器会通过它的自动内存管理为您处理这些问题。如果您想加速垃圾收集,请阅读 G1 垃圾收集器。

【讨论】:

  • 好的,谢谢;我不知道 GC 只有在需要时才会自动运行。
猜你喜欢
  • 2018-12-03
  • 1970-01-01
  • 2011-07-07
  • 2017-09-19
  • 2011-05-12
  • 2014-04-17
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
相关资源
最近更新 更多