用Java引用计数

its*_*dok 8 java concurrency design-patterns

我有一个系统不断耗尽磁盘空间,因为垃圾收集器不会释放持有文件句柄足够快的对象.(文件一直在创建和删除,但由于该进程仍然具有打开的文件句柄,因此操作系统会将其保留在磁盘上).

对象是共享的,所以简单try { ... } finally { close(); }不会这样做.

在我看来,我最好的选择是对对象实现引用计数,并在引用计数为0时关闭文件句柄.但是,我不愿意自己实现它,因为我怀疑存在细微的问题关于并发性.

可悲的是,谷歌搜索"java中的引用计数"并没有带来任何有用的结果.所以我的问题是:是否有任何资源(文章,示例代码,库)可以帮助实现引用计数?

Tho*_*sen 8

不要依赖垃圾收集器.故意设计不可靠.

如果"共享"意味着你在代码中的几个地方使用它,所以你不能只关闭它,我建议你改变你的代码以拥有一个中央文件池,你可以"检查"一个文件句柄用于你的代码在本地.然后close()过程将文件句柄返回到池.跟踪您的句柄,当给定文件的所有句柄返回到池时,您关闭文件.


Ale*_*sky 7

遗憾的是,谷歌搜索“java中的引用计数”并没有带来任何有用的结果。

可悲的是,8年后,情况依然如此。

但是,不再了!我提取了Netty 的引用计数位,对它们进行了相当多的打磨,并将它们制作成一个单独的库almson-refcount

基本的引用计数功能简单明了。有一个基类,ReferenceCountedObject. 它有一个可重写的方法,destroy. 它提供retainrelease使用线程安全且高效的 AtomicFieldUpdater 管理内部引用计数器。release将在同一线程上调用destroy,并且由于不同调用之间的内存排序语义,即使在多线程应用程序中,release您也无需担心线程安全性。destroy该类实现AutoCloseable并提供了一个close简单调用的方法release。这使得它可以在 try-with-resources 中使用。

没有最终确定机制会destroy在您忘记调用释放时尝试调用!最终确定带来了巨大的挑战,包括并发问题,甚至过早确定,特别是在一般情况下。(如果您坚持使用终结器,您仍然可以使用它们或更高性能的java.lang.ref.Cleaner.)

相反,有一个巧妙的泄漏检测系统。它使用类似的机制来完成。因为它的唯一职责是检测泄漏并记录调试信息,所以您无需执行任何操作即可使其正常工作(除了打开它)。

与 Netty 相比,主要变化是:

  • 所有引用计数对象的实际可用基类。
  • 更优雅的界面,更少的方法。
  • 更简单、更干净的代码,更少的麻烦。
  • 改进了检漏仪的文档、预设和输出。