finalize方法由jvm在对象不可达且重写该方法时,将其标记为“需终结”并放入finalizer队列,再由低优先级单线程异步调用,最多执行一次;java 9起废弃,18起标记forremoval,21中底层已大幅移除。

finalize 方法在对象被垃圾回收前**可能**被执行,但不保证、不及时、不可控——它不是资源清理的可靠手段,而是 JVM 早期设计中一个已被淘汰的机制。
finalize 是怎么被调用的
当一个对象不再被任何强引用可达,且其类重写了 finalize(),JVM 会做以下事情:
- 将该对象标记为“需终结”,并放入一个叫 Finalizer 队列 的内部队列中
- 由一个低优先级、单线程的 Finalizer 线程 异步取出并调用它的 finalize() 方法
- 该方法最多执行一次;即使对象在 finalize() 中“复活”(比如赋值给静态变量),也不会再次触发
- 只有等 finalize() 执行完,且对象再次不可达,下一次 GC 才真正回收内存
为什么不推荐使用
它表面上提供“最后清理机会”,实际在工程实践中充满风险:
- 不保证执行:JVM 可能因内存充足、GC 未触发、进程提前退出等原因,完全跳过 finalize
- 严重拖慢回收:含 finalize 的对象必须经历至少两次 GC,延迟释放,容易堆积导致 OOM
- Finalizer 线程易卡死:该线程无超时、不可中断,一旦某个 finalize 里做了 IO、等待锁或死循环,整个队列都会阻塞
- 异常被静默吞掉:finalize 中抛出未捕获异常,线程终止,后续所有终结操作停止,毫无提示
- 允许对象复活,破坏 GC 语义:this 被重新赋值后,对象逃过回收,但状态已错乱,还可能被重复终结
- 子类易遗漏 super.finalize():导致父类清理逻辑丢失,且编译器不会提醒
现代 Java 怎么正确管理资源
替代方案明确、标准、可控,按场景选择即可:
- 绝大多数 I/O 资源(文件流、数据库连接、Socket):实现 AutoCloseable,配合 try-with-resources,作用域结束自动关闭
- 需要异步/延迟清理的 native 资源(如 DirectByteBuffer、自定义内存池):用 Cleaner(Java 9+),基于虚引用,不阻塞 GC,清理动作无法访问原对象
- 老代码或简单场景:显式调用 close() 或 shutdown(),配合 try-finally 保障执行
Finalize 现在是什么状态
它早已不是“慎用”,而是被官方彻底否定:
- Java 9 标记为 @Deprecated
- Java 18 起标注 forRemoval = true
- Java 21 中 HotSpot 已大幅移除底层支持,部分 JVM 模式下根本不会调用
- JFR(Java Flight Recorder)等监控工具已停止采集相关指标
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











