finalize机制已被彻底淘汰,cleaner是官方推荐替代方案,它基于虚引用、不阻塞gc、线程安全、可显式触发且杜绝对象复活;java 9起废弃,21版大幅移除底层支持。

Java 中 finalize 机制已被彻底淘汰,Cleaner 是官方推荐的替代方案——它不依赖 GC 触发、不阻塞回收、线程安全,还能显式触发清理。
为什么 finalize 必须被替换
finalize 的执行完全不可控:JVM 不保证调用、不承诺时机、甚至可能跳过;对象需经历两次 GC 才能回收,Finalizer 线程是单线程且低优先级,一个卡住就导致整个队列积压,引发内存泄漏和 OOM;更危险的是“对象复活”——在 finalize 里把 this 赋给静态变量,会让本该死亡的对象重新强可达,破坏 GC 基础。Java 9 标记废弃,Java 18 标注 forRemoval = true,Java 21 已大幅移除底层支持。
Cleaner 的核心优势
Cleaner 基于虚引用(PhantomReference)实现,与对象生命周期解耦:
- 注册后不持有对象强引用,不影响 GC 速度
- 清理动作由独立守护线程(默认名
Cleaner-0)异步执行,不干扰用户线程或 GC 线程 - 支持手动调用
clean()提前释放资源,适合连接池、缓存等需主动控制的场景 - 清理逻辑无法访问原对象,天然杜绝“复活”和状态错乱
- 异常不会静默吞掉,可捕获并记录日志
如何用 Cleaner 替换 finalize
以管理 native 内存为例:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 声明静态
Cleaner实例:private static final Cleaner cleaner = Cleaner.create(); - 在构造时注册清理动作:
private final Cleanable cleanable = cleaner.register(this, () -> freeNativeResource()); - 若需提前释放(如 close() 方法中):
cleanable.clean(); - 无需重写任何方法,也不继承或修改类结构
对比旧式 finalize,Cleaner 把控制权交还给业务代码,时机明确、行为可测、风险可控。
其他可靠替代方式
并非所有场景都必须用 Cleaner:
- 流、连接、通道类应实现
AutoCloseable,配合try-with-resources—— 资源离开作用域即释放,最及时、最直观 - 需要精确控制清理时机(如框架层管理 DirectByteBuffer)可用
PhantomReference + ReferenceQueue,但需自行轮询和调度,Cleaner 已是其封装好的标准用法 - 简单资源(如线程池、定时器)直接提供
shutdown()或close()方法,由调用方显式管理
Cleaner 不是“另一个 finalize”,而是面向现代 JVM 的轻量、异步、可组合的资源治理工具。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










