通过自定义垃圾收集器防止本机内存泄漏?

时间:2012-01-13 09:24:43

标签: java java-native-interface native

假设我在java中编写一个API,它引用了一些本地C库,需要显式调用析构函数。如果没有调用析构函数,我的本机内存就会耗尽。

有没有办法通过垃圾收集器以某种方式调用析构函数来保护我的API用户不显式调用析构函数? (也许基于我对使用的本机内存大小的一些估计?)

我知道Java没有垃圾收集器作为Java API的一部分,但也许有一些方法可以实现它?

3 个答案:

答案 0 :(得分:3)

如果您可以控制对象的创建,则可以使用带有ReferenceQueue的构造函数使用WeakReference引用它们。当它们超出范围时,引用将排队,您可以让自己的线程轮询队列并调用一些清理功能。

为什么呢? 嗯,它比为类添加终结器稍微有效一些(因为它会强制gc对它们进行一些特殊处理)。

修改:以下两个(同一篇文章的变体)描述了它: http://java.sun.com/developer/technicalArticles/javase/finalization/ http://www.devx.com/Java/Article/30192

当Peter Lawrey说:

时,Peter Lawrey有一个非常好的观点
  

即便如此,等待GC清理可能效率低下,如果需要,您可能希望公开一种明确清理资源的方法。

每当您可以假设您的用户使用Java7时,请查看java.lang.AutoCloseable,因为它可以帮助他们在使用新的try-with-resources时自动执行此操作。

答案 1 :(得分:2)

除了使用finalize()之外,如果资源不足以进行调用,则可能需要触发GC,但GC尚未运行。

ByteBuffer.allocateDirect()存在此问题。它需要GC来清理其ByteBuffers,但是,您可以在触发GC之前达到最大直接内存,因此代码必须检测到这一点并明确触发System.gc()

即便如此,等待GC清理可能效率低下,如果需要,您可能希望公开一种明确清理资源的方法。

答案 2 :(得分:1)

当Java对象即将成为GCd时,垃圾收集器将调用Java对象的finalize(),并且在finalize中,您可以调用析构函数。只需为每个需要调用的析构函数创建一个 new Java对象,并保持对该Java对象的引用,直到您想要调用析构函数为止。

实际上,finalize()迟早会被调用(即使技术上Java不能保证任何特定对象永远是GCd)。唯一的例外是当进程关闭时对象仍然存在:那么它可能确实永远不会得到GCd。