Java API使用finalizers来释放由C调用分配的内存时出现内存不足错误。

21 浏览
0 Comments

Java API使用finalizers来释放由C调用分配的内存时出现内存不足错误。

我们有一个Java API,它是一个C API的包装器。因此,我们最终得到几个Java类,它们是C++类的包装器。

这些类实现了finalize方法,以释放为它们分配的内存。

一般来说,这可以很好地工作。然而,在高负载情况下,我们会出现内存耗尽异常。

内存转储表明,几乎所有的内存(本例中约6Gb)都被最终器队列和等待最终化的对象填满了。

相比之下,单独的C API从不超过约150 Mb的内存使用率。

在低负载下,Java实现可以无限制地运行。因此,这似乎不是内存泄漏。只是在高负载下,需要终止的新对象的生成速度比最终器的执行速度更快。

显然,“正确”的解决方法是减少创建的对象数量。然而,那是一个重要的任务,需要一段时间。在此期间,是否有机制可以帮助减轻这个问题?例如,给GC更多的资源。

admin 更改状态以发布 2023年5月24日
0
0 Comments

Java中的虚引用是替代finalizers的一种选择。

虚引用允许您更好地控制资源回收过程。

  • 您可以将显式资源处理(例如使用资源构建的try)与GC基础处理相结合
  • 您可以使用多个线程进行事后清理

虽然使用虚引用很复杂。在本文中,您可以找到基于虚引用的资源清理的最小示例。

在现代Java中,还有Cleaner类,它也基于虚引用,但提供了基础设施(引用队列,工作线程等)以便于使用。

0
0 Comments

Java是围绕着一种想法设计的,即终止器可用作超出范围的对象的主要清理机制。当对象的总数量足够小以至于\"总是扫描所有\"垃圾回收器的开销可以接受时,这种方法可能几乎可行,但在具有分代垃圾回收器的系统中(几乎所有JVM实现都会有这种回收器,因为它相比总是扫描所有的回收器有巨大的速度提升)中,终结可能是适当的清理措施的情况相对较少。\n\n只要有可能,使用闭合和try-with-resources结构是一种非常优越的方法。无法保证终止器方法将按照任何时间度执行,并且有许多情况可能会防止它们被完全执行,比如相互关联对象的模式。虽然终止器可以用于一些目的,比如识别在持有资源时被错误弃用的对象,但是只有极少数目的可以使用它作为适当的工具。\n\n如果确实需要使用终止器,那么您应该了解一个重要的原则:与流行观点相反,终止器不会在对象实际被垃圾回收时触发——它们会在对象要被垃圾回收但存在某处(包括但不限于对象自身的终结器)终止器时触发。只要在任何局部变量、任何其他对象中存在任何引用或任何尚未运行完成的终止器的任何对象中存在对象的引用,就不能实际回收这个对象。此外,为避免在每个垃圾收集周期中检查所有对象,存活了一段时间的对象将在大多数GC周期中获得\"免费通行\"。因此,如果具有终止器的对象在被废弃之前存活了一段时间,它的终止器可能需要很长时间才能运行,并且它将使它持有的引用对象保持足够长的时间,以便它们也可能获得\"免费通行\"。\n\n因此,我建议尽可能在使用终结器时,要将它们限制在私有对象中,并避免它们保持对除清理任务所需的任何内容以外的所有内容的强引用。

0