★finalize 函数的调用机制

  俺经常啰嗦:“了解本质机制的重要性”。所以今天也得先谈谈 finalize 函数的调用机制。在聊之前,先声明一下:Java虚拟机规范(见“这里”),并没有硬性规定垃圾回收该不该搞,以及该如何搞。所以俺这里提到的 finalize 函数的调用机制,或许适用于大多数 JVM,但【不保证】适用于所有的 JVM。

◇何时被调用?

  finalize 啥时候才会被调用捏?一般来说,要等到JVM开始进行垃圾回收的时候,它才【有可能】被调用。而 JVM 进行垃圾回收的时间点是【非常】不确定的,依赖于各种运行时的环境因素。具体细节可以参见“本系列前一帖”。正是由于 finalize 函数调用时间点的不确定,导致了后面提到的某些缺点。

◇谁来调用?

  说完何时调用,咱接着来聊一下被谁调用?
  常见的 JVM 会通过 GC 的垃圾回收线程来进行 finalize 函数的调用。由于垃圾回收线程比较重要(人家好歹也是 JVM 的一个组成部分嘛),为了防止 finalize 函数抛出的异常影响到垃圾回收线程的运作,垃圾回收线程会在调用每一个 finalize 函数时进行 try/catch,如果捕获到异常,就直接丢弃,然后接着处理下一个失效对象的 finalize 函数。

★对 finalize 函数的误解和误用

◇把 finalize 理解为“析构函数”

  学过 C++ 的同学应该都知道“析构函数”(不懂 C++ 的同学直接跳过此小节)。C++ 析构函数是在对象离开作用域的当口,【立即】被调用的。
  很多从 C++ 转 Java 的同学会想当然地把 Java 的 finalize 函数牵强附会成 C++ 的析构函数(两者确实有某些相似之处)。然而,现实往往不是这么美好滴。由于 Java 的 finalize 函数和 C++ 的析构函数之间有许多非常【关键性】的差异,那些把 finalize 拿来当析构函数用的同学,是注定要碰壁滴(具体请看本文后面“finalize 函数的缺点”)。

◇依靠 finalize 来释放资源

  很多同学寄希望于通过 finalize() 来完成类对象中某些资源的释放(比如关闭数据库连接之类)。
  有这种企图的同学,请注意看本文后面的“finalize 函数的缺点”!

★使用 finalize 函数的注意事项

  下面介绍的注意事项,有些可能和性能优化关系不大,俺也一并列出来。

◇调用时间不确定——有资源浪费的风险

  前面已经介绍了调用机制。同学们应该认清【finalize 的调用时机是很不确定的】这样一个事实。所以,假如你把某些稀缺资源放到 finalize() 中释放,可能会导致该稀缺资源等上很久很久很久以后才被释放。这可是资源的浪费啊!
  另外,某些类对象所携带的资源(比如某些 JDBC 的类)可能本身就很耗费内存,这些资源的延迟释放会造成很大的性能问题。

◇可能不被调用——有资源泄漏的风险

  很多同学误以为 finalize() 总是会被调用,【其实不然】。在某些情况下,finalize() 压根儿不被调用。比如在 JVM 退出的当口,内存中那些对象的 finalize 函数可能就不会被调用了。
  俺估摸着:还有同学在打 “runFinalizersOnExit” 的主意,来确保所有的 finalize 在 JVM 退出前被调用。但是,很可惜也很遗憾,该方法从 JDK 1.2 开始,就已经被废弃了。即使该方法不被废弃,也是有很大的线程安全隐患滴!企图打这个主意的同学,趁早死了这条心吧!
  从上述可以看出,一旦你依赖 finalize() 来帮你释放资源,那可是很不妙啊(【有资源泄漏的危险】)!关于资源泄漏的严重性,俺在“这里”曾经提到过。很多时候,资源泄露导致的性能问题更加严重,万万不可小看。

◇对象可能在 finalize 函数调用时复活——有诈尸的风险

  诈尸的情况比较少见,不过俺还是稍微提一下。
  本来,只有当某个对象已经失效(没有引用),垃圾回收器才会调用该对象的 finalize 函数。但是,万一碰上某个变态的程序员,在 finalize() 函数内部再把对象自身的引用(也就是 this)重新保存在某处,也就相当于把自己复活了(因为这个对象重新有了引用,不再处于失效状态)。这种做法是不是够变态啊 :-)
  为了防止发生这种诡异的事情,垃圾回收器只能在每次调用完 finalize() 之后再次去检查该对象是否还处于失效状态。这无形中又增加了 JVM 的开销。
  随便提一下。由于 JDK 的文档中规定了(具体参见“这里”),JVM 对于每一个类对象实例最多只会调用一次 finalize()。所以,对于那些诈尸的实例,当它们真正死亡时,finalize() 反而不会被调用了。这看起来是不是很奇怪?

◇要记得自己做异常捕获

  刚才在介绍 finalize() 调用机制时提到,一旦有异常抛出到 finalize 函数外面,会被垃圾回收线程捕获并丢弃。也就是说,异常被忽略掉了(异常被忽略的危害,“这里”有提到)。为了防止这种事儿,凡是 finalize() 中有可能抛出异常的代码,你都得写上 try catch 语句,自己进行捕获。

◇要小心线程安全

  由于调用 finalize() 的是垃圾回收线程,和你自己代码的线程不是同一个线程;甚至不同对象的 finalize() 可能会被不同的垃圾回收线程调用(比如使用“并行收集器”的时候)。所以,当你在 finalize() 里面访问某些数据的时候,还得时刻留心线程安全的问题。

★结论

  前面废了这么多话,最后稍微总结一下。俺窃以为:finalize 实在是 Java 的鸡肋。或许它对于【极少数】程序员有用,但对于大多数人(包括俺自个儿),这玩意儿压根儿没啥好处。大伙儿还是尽量不用为妙。

转载于:https://blog.51cto.com/14314113/2388466

AJPFX讲解Java 性能优化[4]:关于 finalize 函数相关推荐

  1. 赠书:《Java性能优化实践》,众多业内大佬推荐阅读

    没有捷径可走的 Java 性能优化 多年来,用 Google 搜索 Java performance tuning,出现的三篇最热门文章之一是于 1997 年到 1998 年左右发表的文章,这篇文章在 ...

  2. 新书上市 | 《Java性能优化实践》,众多业内大佬推荐阅读

    没有捷径可走的 Java 性能优化 多年来,用 Google 搜索 Java performance tuning,出现的三篇最热门文章之一是于 1997 年到 1998 年左右发表的文章,这篇文章在 ...

  3. 拉勾教育 | Java 性能优化实战 21 讲

    开篇词 开篇词 | Java 性能优化,是进阶高级架构师的炼金石 你好,我是李国.作为<Java 性能优化与面试 21 讲>这个课程的作者,我先来简单介绍下自己. 我曾任京东金融.陌陌科技 ...

  4. 推荐:Java性能优化系列集锦

    Java性能问题一直困扰着广大程序员,由于平台复杂性,要定位问题,找出其根源确实很难.随着10多年Java平台的改进以及新出现的多核多处理器,Java软件的性能和扩展性已经今非昔比了.现代JVM持续演 ...

  5. Java 性能优化的七个方向

    了解了优化目标后,那接下来应该从哪些方面入手呢?本文主要侧重于理论分析,我们从整体上看一下 Java 性能优化都有哪些可以遵循的规律.本文主讲理论.关于实践,后续的文章会用较多的案例来细化本文的知识点 ...

  6. Java性能优化,操作系统内核性能调优,JYM优化,Tomcat调优

    文章目录 Java性能优化 尽量在合适的场合使用单例 尽量避免随意使用静态变量 尽量避免过多过常地创建Java对象 尽量使用final修饰符 尽量使用局部变量 尽量处理好包装类型和基本类型两者的使用场 ...

  7. [原创]Java性能优化权威指南读书思维导图

    [原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt    Binu John 译者: 柳飞 ...

  8. Java性能优化技巧

    Java性能优化技巧 参考了些书籍,网络资源整理出来,适合于大多数Java应用 在JAVA程序中,性能问题的大部分原因并不在于JAVA语言,而是程序本身.养成良好的编码习惯非常重要,能够显著地提升程序 ...

  9. java strim性能_你所不知道的Java性能优化之String!

    Java性能优化之String字符串优化 1.字符串对象及其特点 Java中八大基本数据类型没有String类型,因为String类型是Java对char数组的进一步封装. String类的实现主要由 ...

最新文章

  1. 30个Oracle语句优化规则详解
  2. 技术干货 | 视频最佳体验之自适应调节系统
  3. Android GestureDetector方法详解
  4. 028 -bash-4.1$ 出现故障的原理及解决办法?
  5. Docker笔记(基础篇)
  6. 聊天室私人聊天原理_如何设置极其安全的私人群组聊天
  7. SPSS——非参数检验——1-Sample K-S 单个样本(Kolmogorov-Smirnov)柯尔莫哥洛夫-斯米诺夫检验
  8. 全网优惠券、红包获取api
  9. SWAT入门小问题的解决
  10. 皇家骑士团 100问
  11. android p小米note3,小米note3|RROS-V7.0|安卓9.0|最强大的自定_最新最全的小米Note3ROM刷机包下载、刷机...
  12. [Java]简单易懂的并发教程
  13. 获取当年的法定节假日和周末_通过可配置的周末和节假日添加工作日
  14. 4家运营商创建NFV MANO开源工作组
  15. 程序员做什么副业最轻松最赚钱?
  16. Socket编程---read方法阻塞问题
  17. Doo-Sabin细分算法
  18. 软件开发工具与环境 (课程代码:07169)
  19. emmet插件的导入与实用
  20. 2022年起重机司机(限门式起重机)考试题模拟考试题库及答案

热门文章

  1. 给脚本添加到环境变量_让你的脚本可以在任意地方都可执行的几个方法
  2. php 相册分类,这款不需要网络就可以智能识别分类照片,让你的相册不再混乱...
  3. java transaction cn_GitHub - cnzebra/tcc-transaction: tcc-transaction是TCC型事务java实现
  4. python设置行号_Python_添加行号
  5. python如何计算个人gpa_使用While循环(Python)计算GPA
  6. 1.1 一个简单的脚本
  7. 使用maven时报错Dynamic Web Module 3.1 requires Java 1.7 or newe
  8. Linux下安装oracle的过程
  9. C++异常(exception)第一篇--综合讲解
  10. 串口项目——Cseiralport类的应用(1 )