finalize()如何在java中工作?

所以,我最近在Java中发现了finalize方法(不知道为什么我之前错过了它,但它确实存在)。 这似乎可能是我正在处理的许多问题的答案,但我想首先获得更多信息。

在线,我发现这个图表说明了垃圾收集和完成的过程:

这描述了涉及finalize和JGC的操作顺序:

几个问题:

  1. 这发生在一个单独的线程中,对吗?
  2. 如果我在finalize期间实例化一个新对象会发生什么? 这是允许的吗?
  3. 如果我从finalize调用静态方法会发生什么?
  4. 如果我在finalize中建立对象的新引用会发生什么?

我想我应该解释为什么我感兴趣。 我经常使用LWJGL,似乎如果我可以使用finalize来使Java对象自动清理OpenGL资源,那么我可以在API方面做一些非常好的事情。

我认为没有任何关于将使用什么线程的保证。 可以实例化新对象并且可以调用静态方法。 建立对象的新引用将阻止它被垃圾回收,但不会再次调用finalize方法 – 您不希望这样做。

清理资源正是finalize方法的用途,所以你应该做得很好。 但是有几个警告:

不保证调用该方法。 如果你绑定了在程序停止时不会自动释放的资源,则不依赖于finalize

调用方法时无法保证。 记忆力紧张,这将更快。 拥有大量的可用内存,如果有的话,它将会更晚。 这可能适合你:拥有大量内存,你可能不会那么担心释放资源。 (虽然挂在他们身上可能会干扰同时运行的其他软件,在这种情况下你担心。)

我的用法解决方案是使用某种处理方法进行清理。 如果可以的话,我会在某些时候明确地称之为,并尽快。 然后我添加一个只调用dispose方法的finalize方法。 (注意,当多次调用时, dispose方法必须表现良好!实际上,通过这种编程,我可能会在finalize之外调用几次,不确定以前的调用是否成功,但是希望它被有效地调用为尽快。)现在,理想情况下,一旦我不再需要它,我的资源就会被释放。 但是,如果我用资源丢失了对象的跟踪,那么当内存不足时我会需要帮助, finalize方法会让我失望。

当Java Garbage Collector检测到不存在对该特定对象的引用时,将调用finalize()。 finalize()由所有Java对象通过Object类inheritance。

据我所知,你可以毫无困难地从finalize()方法调用静态方法调用我可以从finalize()建立一个新的引用 – 但是我会说这是糟糕的编程实践。

你不应该依赖finalize()进行清理,最好随时清理。 我更喜欢使用try,catch,最后清理,而不是使用finalize()。 特别是,通过使用finalize(),您将使JVM保留可终结对象引用的所有其他对象,以防它调用它们。 这意味着您可能不需要使用内存。 更重要的是,这也意味着你可以让JVM永远不会最终处置对象,因为他们必须抓住它们,因为其他对象的最终方法需要它,例如竞争条件。

另外,请考虑完全有可能不会调用GC。 因此,您实际上无法保证将永远调用finalize()。

在完成资源时清理资源,并且不依赖于finalize()来完成它是我的建议。

首先,请记住,不能保证甚至可以为所有对象运行终结。 您可以使用它来释放与对象关联的本机代码中分配的内存,但对于纯Java代码,大多数用例只是执行清理资源的“备份”机制。 这意味着在大多数情况下,您应该手动释放资源,如果您忘记以标准方式执行此操作,终结器可能只是一种帮助来清理。 但是,您不能将它们用作清理的唯一或主要机制。 更一般地说,您不应该编写任何正确性取决于正在运行的终结器的代码。

广告1.据我所知,没有保证什么线程调用finalize() ,虽然在实践中这可能是GC线程之一。

广告2.允许实例化新对象。 但是,在终结器中处理对象引用存在许多缺陷。 特别是,如果存储对某些活动对象中最终确定的对象的硬引用,则可以防止清除即将被垃圾收集的对象。 如果失去控制,这种物体复活可能会导致资源耗尽。 另外,请注意finalize()exception – 它们可能会停止最终确定,但是没有自动的方法让您的程序了解它们。 您需要将代码包装在try-catch块中并自己传播信息。 此外,终结器的长执行时间可能导致对象队列建立并消耗大量内存。 本JavaWorld文章中描述了一些其他值得注意的问题和限制。

广告3.从终结器调用静态方法应该没有任何问题。

广告4.如第2点所述,可以通过在最终确定期间将对象放置在另一个活动对象中来防止对象被垃圾收集(以使其复活)。 然而,这是棘手的行为,可能不是好的做法。

总而言之,您不能依赖终结器来清理资源。 你需要手动处理,你的情况下的终结器最多可以用作备份机制,以便在一定程度上进行草率编码后进行掩盖。 不幸的是,这意味着您通过使用终结器清理OpenGL资源来使API更好的想法可能不会起作用。