Cleaner:Java的一种新资源释放方式
引言
在JDK9中新增了Cleaner类,该类的作用是用于替代finalize方法,更有效地释放资源并避免内存泄漏。
基本概念和使用
在JEP260提案中,封装了大部分Sun
包内部的API之余,还引入了一些新的API,其中就包含着Cleaner
这个工具类。 Cleaner
承担着替换finalize
方法的作用,为了解决finalize
方法的性能问题、安全问题以及不可靠。
Cleaner 类的主要方法和属性
如何创建和使用 Cleaner 对象
- 使用
Cleaner.create()
创建Cleaner对象。 - 调用
cleaner.register()
方法,传入监听的对象以及回收后要执行的逻辑。其中,逻辑中不能带有监听对象的引用,否则对象将永远无法被回收。
实际应用和示例
典型的 Cleaner 类使用场景和示例代码
在JDK1.2中,就已经有这个类的内部实现了,不过是在sun
包中实现的。由于是内部类不建议在生产代码中直接使用。不过sun包下的Cleaner类和lang
包下的Cleanr类的功能是类似的。Cleaner在JDK中最典型的实现就是堆外内存的回收。我们申请到一个堆外内存后,是无法手动将该堆外内存进行显式回收的,只能等待JVM来自动回收该内存。其中,自动回收的操作就是使用到了Cleaner工具类,在DirectByteBuffer
的构造方法中,申请到堆外内存后,就会将堆外内存地址、申请容量以及实际内存大小传入到Deallocator类中进行空间的回收。Deallocator类集成了Runnable接口,在run方法中就会将对应地址的堆外内存回收。
优点和局限性
Cleaner 类相比 Finalizer 和 PhantomReference 的优势
类型 | 自动化清理 | 易用性 | 安全性 | 性能影响 |
---|---|---|---|---|
Cleaner | 是 | 开箱即用 | 更强 | 较小 |
Finalizer | 是 | 开箱即用 | 较弱 | 较大 |
PhantomReference | 否 | 需要与引用队列相结合,额外代码工作量 | 较弱 | 较小 |
Cleaner 类和手动调用Close方法的区别
操作 | 执行时机 | 确定性 | 是否自动化清理 | 资源泄漏风险 |
---|---|---|---|---|
Cleaner | 对象被回收时隐式调用 | 执行时机无法控制 | 是 | 低(只要对象不再可达,就会自动清理) |
调用Close方法 | 代码显示调用 | 只要调用,一定执行 | 否 | 高(如果忘记调用 close 方法,可能会导致资源泄露) |
Cleaner 类的潜在问题和限制
- 每注册一个Cleaner类,就会新开一条线程用于监听目标对象是否已经进入到引用队列。直到目标对象被回收后,新线程才结束。
- Cleaner回收时间点无法控制。
- 不能替换所有的资源释放,必要时还是需要显式执行Close方法。
- 无法控制传入的回收执行逻辑,可能导致性能问题。
转载自:https://juejin.cn/post/7342704061828595749