首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java API中出现内存不足错误,该API使用终结器来释放由C调用分配的内存

Java API中出现内存不足错误,该API使用终结器来释放由C调用分配的内存
EN

Stack Overflow用户
提问于 2020-10-08 22:33:03
回答 2查看 64关注 0票数 0

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

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

一般来说,这样做效果很好。然而,在高负载的情况下,我们会遇到内存不足的异常。内存转储表示实际上所有内存(在本例中约为6 6Gb )都被终结器队列和等待完成的对象填满。

相比之下,C API本身的内存使用量永远不会超过150Mb左右。

在低负载下,Java实现可以无限运行。所以这看起来不像是内存泄漏。这似乎只是在高负载下,需要终结器的新对象的生成速度比终结器的执行速度更快。

显然,“正确的”修复方法是减少创建的对象数量。然而,这是一项重要的任务,需要一段时间。同时,有没有一种机制可以帮助缓解这个问题?例如,通过给GC更多的资源。

EN

回答 2

Stack Overflow用户

发布于 2020-10-08 23:42:41

Java的设计思想是终结器可以用作超出作用域的对象的主要清理机制。当对象的总数小到可以接受“始终扫描所有内容”垃圾收集器的开销时,这种方法可能几乎是可行的,但在具有分代垃圾收集器的系统中,完成是适当的清理措施的情况相对较少(几乎所有JVM实现都会有,因为与总是扫描所有内容相比,它提供了巨大的速度提升)。

只要可行,将Closable与try- with -resources结构一起使用是一种非常优越的方法。不能保证finalize方法将以任何程度的及时性被调用,并且在许多情况下,相关对象的模式可能根本阻止它们被调用。虽然finalize可以用于某些目的,例如识别在持有资源时被不适当地丢弃的对象,但对于相对较少的目的来说,它将是适当的工具。

如果你确实需要使用终结器,你应该理解一个重要的原则:与流行的想法相反,终结器不会在对象实际被垃圾回收时触发--它们在对象本应被垃圾回收时触发,但在某个地方存在终结器,包括但不限于对象自己的终结器。任何对象都不能被垃圾回收,因为它的引用存在于任何局部变量中,存在于任何其他存在引用的对象中,或者存在于任何具有未运行到完成的终结器的对象中。此外,为了避免在每个垃圾收集周期中检查所有对象,在大多数GC周期中,将给予已存活一段时间的对象一个“自由通行证”。因此,如果具有终结器的对象在被丢弃之前存活了一段时间,那么它的终结器可能需要相当长的时间才能运行,并且它将保留其引用的对象足够长的时间,以便它们也可能获得“自由传递”。

因此,我建议,在可能的范围内,即使有必要使用finalizer,您也应该将它们的使用限制在私有对象上,这样就避免了对清理任务不显式需要的任何对象的强引用。

票数 3
EN

Stack Overflow用户

发布于 2020-10-09 06:42:18

幻影引用是Java中可用的终结器的替代方法。

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

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

使用幻影引用很复杂,很困难。在this article中,您可以找到一个基于虚拟引用的资源内务的最小示例。

在现代Java语言中,也有基于幻影引用的Cleaner类,但为了便于使用,它提供了基础设施(引用队列、工作线程等)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64264807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档