Java 中的引用计数

2022-09-04 20:16:36

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

对象是共享的,所以简单的对象不行。try { ... } finally { close(); }

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

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


答案 1

不要依赖于垃圾回收器。它被故意设计为不可靠。

如果“共享”意味着您在代码中的多个位置使用它,因此您无法仅关闭它,我建议您将代码更改为具有中央文件池,您可以在其中“签出”要在本地代码中使用的文件句柄。然后,close() 过程将文件句柄返回到池中。跟踪句柄,当给定文件的所有句柄都返回到池中时,您将永久关闭该文件。


答案 2

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

可悲的是,8年后,这种情况仍然如此。

但是,不再!我拿出了Netty的参考计数位,将它们打磨了不少,并将它们制作成一个单独的库,almson-refcount

基本的参考计数功能简单明了。有一个基类 。它有一个可重写的方法。它使用线程安全和高效的原子字段更新程序提供并管理内部引用计数器。 将调用同一线程,并且由于不同调用之间的内存排序语义,即使在多线程应用程序中,您也不必担心线程安全性。该类实现并提供一个方法,该方法仅调用 。这允许它在资源试用中使用。ReferenceCountedObjectdestroyretainreleasereleasedestroyreleasedestroyAutoCloseablecloserelease

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

相反,有一个聪明的泄漏检测系统。它使用与最终确定类似的机制。由于它的唯一职责是检测泄漏并记录调试信息,因此无需执行任何操作即可使其正常工作(除非将其打开)。

与Netty相比,主要变化的是:

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

推荐