使用终结器以释放C调用分配的内存的Java API中的内存不足错误

如何解决使用终结器以释放C调用分配的内存的Java API中的内存不足错误

我们有一个Java API,它是C API的包装。 这样,我们最终得到了几个java类,它们是C ++类的包装器。

这些类实现finalize方法,以释放已为其分配的内存。

通常,这很好。但是,在高负载情况下,我们会遇到内存不足的异常。 内存转储表明实际上所有内存(在这种情况下约为6Gb)都已填充有终结器队列和等待终结的对象。

为进行比较,C API自身的内存使用量永远不会超过150 Mb。

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

很显然,“正确”的解决方法是减少所创建对象的数量。但是,这是一项艰巨的任务,需要一段时间。同时,是否有一种机制可以缓解此问题?例如,通过为GC提供更多资源。

解决方法

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

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

如果确实需要使用终结器,则应该了解一个重要原则:与流行的看法相反,终结器不会在对象实际被垃圾回收时触发” –它们将在对象被回收时触发但是存在某个终结器(包括但不限于该对象自己的终结器),而在任何局部变量和任何其他对象中都存在对它的任何引用时,实际上无法对其进行垃圾回收此外,为避免必须在每个垃圾收集周期中检查所有对象,已使用了一段时间的对象将获得“自由通过”的权限,以便在任何垃圾回收周期检查所有对象。大多数GC周期。因此,如果带有终结器的对象在被丢弃之前还存活了一段时间,则它的终结器可能需要花费相当长的一段时间才能运行,并且它将保留其引用的对象足够长的时间,以至于它们可能还可以获得“免费通行证”。>

因此,我建议即使在有必要使用终结器的情况下,也应将它们的使用范围限制为私有对象,从而避免持有对清理任务中未明确需要的任何内容的强引用。

,

虚拟引用是Java中可用的终结器的替代方法。

虚拟引用使您可以更好地控制资源回收过程。

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

使用幻象引用非常困难。在this article中,您可以找到虚拟引用基础资源内务处理的最小示例。

在现代Java中,也有Cleaner类,它也基于幻像引用,但提供了易于使用的基础结构(引用队列,工作线程等)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?