关于finalize()方法(总结)

本文详细介绍了Java中finalize()方法的作用及使用场景。该方法在对象被垃圾回收前调用,用于释放非内存资源,但其执行时机不确定且易引发问题。文章推荐避免使用此方法,并提供了正确实现的示例。

finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象(凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。
特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,比如:一个socket链接,在对象初始化时创建,整个生命周期内有效,那么就需要实现finalize,关闭这个链接。
使用finalize还需要注意一个事,调用super.finalize();

一个对象的finalize()方法只会被调用一次,而且finalize()被调用不意味着gc会立即回收该对象,所以有可能调用finalize()后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会调用finalize(),产生问题。
所以,推荐不要使用finalize()方法,它跟析构函数不一样。

1.object定义
protected void finalize() //定义为子类可见

2.执行时机不可预知
当一个对象变得不可触及时,垃圾回收器某个时期会回收此对象。
当回收对象之前会调用finalize方法,这类似于人类临终之前必须做一件事情:写遗言。
因为GC是不确定性的(这跟JVM相关),所以finalize方法的执行具有不可预知性。

3.finalize忽略异常
即finalize代码中若出现异常,异常会被忽略

4.finalize使用
什么时候使用?一般来说,finalize被作为第二种安全网来使用,如FileInputStream类,
当对象回收时,有可能资源为释放,所以这里第二次来确认(那也总比不释放强吧,虽然具体释放时机未定)

protected void finalize() throws IOException { 
    if (fd != null) { 
        if (fd != fd.in) { 
            close(); 
        } 
    } 
} 

注意:某些用到finalize的地方,你必须像如下所示,显式调用回收链。

protected void finalize() throws IOException { 
    try{ 
                              ... 
    }finally{ 
            super.finalize(); 
    } 
} 

5.<\effective java>建议:尽量不要使用finalize,除非以它作为安全网,或是为了终结非关键的原生资源。

参考地址:http://caizi0413.iteye.com/blog/845727
https://segmentfault.com/q/1010000000094660

<think>我们被要求回答关于Java中finalize方法的作用和使用场景。根据提供的引用材料,我们可以总结如下: 1. **作用**:finalize()是Object类中定义的一个protected方法,用于在垃圾回收器回收对象之前执行一些清理操作。主要作用包括: - 释放非Java资源(如文件句柄、网络连接、数据库连接等)[^4][^5]。 - 作为对象被回收前的最后一道防线,用于检查对象状态,确保资源被正确释放(例如,在调试时发现资源未释放的情况)[^5]。 2. **使用场景**: - 当对象持有非Java资源(如通过JNI分配的内存、系统资源等)时,可以在finalize()中编写释放这些资源的代码[^4][^5]。 - 用于调试或监控对象被回收的情况,例如检查对象是否在未释放资源的情况下被回收(如上面Tank类的例子)[^5]。 3. **注意事项**(根据引用材料): - finalize()的调用时机不确定:它只会在垃圾回收时被调用,且我们无法知道何时甚至是否会被调用[^3]。因此,不能依赖finalize()来释放关键资源,而应该提供显式的释放方法(如close())[^3]。 - 性能问题:finalize()的执行会延长对象的生命周期(至少一次垃圾回收周期),可能导致内存回收延迟[^1]。 - 避免使用:在Java9之后,finalize()已被标记为deprecated,因为其使用容易导致性能问题和资源泄漏[^1][^5]。推荐使用try-with-resources或显式的资源管理(如AutoCloseable接口)[^1]。 因此,我们可以这样组织回答: **Java中finalize方法的作用和使用场景** 1. **作用**:finalize()是Object类中定义的一个protected方法,用于在垃圾回收器回收对象之前执行清理操作。主要作用包括: - 释放对象持有的非Java资源(如文件句柄、网络连接等)[^4][^5]。 - 作为对象回收前的最后检查点,用于记录对象状态或调试资源泄漏问题(如示例中的Tank类检查是否为空)[^5]。 2. **使用场景**(实际应用有限): - 管理非Java资源:当Java对象通过本地方法(JNI)分配了堆外内存或系统资源时,可在finalize()中调用本地方法释放这些资源[^5]。 - 调试辅助:用于检测对象在未正确释放资源的情况下被回收(如上述Tank示例中,若Tank被回收时仍非空,则打印错误)[^5]。 3. **注意事项与限制**: - **调用时机不确定**:finalize()只会在垃圾回收时被调用,且无法保证执行顺序或时间(甚至可能永不执行)[^3]。因此,不能依赖它来释放关键资源(如数据库连接),否则可能导致资源耗尽。 - **性能开销**:finalize()会延迟对象回收(对象至少存活一个GC周期),增加垃圾回收的负担[^1]。 - **已被弃用**:Java9开始,finalize()被标记为`@Deprecated`,推荐使用`AutoCloseable`接口和`try-with-resources`语法进行显式资源管理[^1][^5]。 **最佳实践**:优先使用显式资源释放机制(如`close()`方法),避免使用finalize()。若必须使用,应确保逻辑简洁且幂等(多次调用无害)[^4]。 §§相关问题§§ 1. 为什么Java9弃用finalize()方法? 2. 如何正确使用try-with-resources管理资源? 3. 除了finalize(),还有哪些方法可以检测资源泄漏? 4. 垃圾回收器如何处理带有finalize()的对象?</think>### Java 中 `finalize()` 方法的作用与使用场景 #### 一、核心作用 1. **资源清理机制** 用于在对象被垃圾回收前**释放非 Java 资源**(如文件句柄、网络连接、数据库链接、Native 内存等)。当对象持有操作系统资源时,可通过重写 `finalize()` 确保资源释放[^4][^5]。 ```java protected void finalize() throws Throwable { closeFileHandle(); // 释放文件句柄 releaseNativeMemory(); // 释放JNI分配的本地内存 } ``` 2. **对象回收前的最后屏障** 作为对象被销毁前的**最后执行机会**,用于执行必须的清理逻辑(即使开发者忘记显式释放资源)[^2][^4]。 3. **调试与状态检查** 可检测对象是否在**非法状态**下被回收(如未关闭的资源),辅助定位资源泄漏问题[^5]: ```java @Override protected void finalize() throws Throwable { if (!isClosed) { System.err.println("资源未关闭!"); // 输出警告 } super.finalize(); } ``` #### 二、使用场景 1. **管理本地资源(Native Resources)** 当 Java 对象通过 JNI(Java Native Interface)调用本地库并分配了堆外内存时,需在 `finalize()` 中释放这些资源[^5]。 > 示例:本地图形库的窗口句柄、音频设备的独占锁。 2. **作为资源泄漏的兜底方案** 当某些资源因编码遗漏未被显式释放(如未调用 `close()`),`finalize()` 可作为最后防线[^4]。 3. **调试与监控** 跟踪对象回收状态,例如: - 验证资源是否在对象销毁前被正确释放[^5] - 统计特定类实例的回收频率 #### 三、关键注意事项 1. **执行时机不确定** `finalize()` **不保证立即执行**,甚至可能永不执行(若 JVM 未触发 GC)。无法依赖其实时性[^3]。 > 实验:循环创建 10,000 个对象后调用 `System.gc()`,部分对象的 `finalize()` 可能延迟数秒才执行[^5]。 2. **性能开销大** - 对象至少经历 **两次 GC** 才能回收(第一次标记并排队,第二次执行 `finalize()`) - 可能引发 **GC 停顿延长**(Finalizer 线程与用户线程竞争) 3. **已被官方弃用** Java 9+ 将 `Object.finalize()` 标记为 **`@Deprecated`**,原因包括: - 资源释放应使用显式方法(如 `AutoCloseable` + `try-with-resources`) - 易引发内存泄漏(`finalize()` 中错误保留对象引用) - 替代方案:`java.lang.ref.Cleaner` 和 `PhantomReference`[^1][^5] #### 四、最佳实践 1. **优先使用显式资源管理** ```java // 正确做法:实现 AutoCloseable class Resource implements AutoCloseable { public void close() { releaseResources(); // 显式释放 } } // 使用 try-with-resources 确保释放 try (Resource res = new Resource()) { // 使用资源 } ``` 2. **若必须使用 finalize()** - 确保逻辑**幂等**(多次调用无害) - 避免在 `finalize()` 中**重建对象引用**(会导致对象复活) - 始终调用 `super.finalize()`[^2] > **总结**:`finalize()` 是 JVM 垃圾回收前的清理钩子,适用于非 Java 资源释放和调试场景。但因执行不可靠、性能差,现代 Java 开发中应避免使用,改用 `AutoCloseable` 等机制[^1][^4][^5]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值