AJPFX浅谈Java性能优化之finalize 函数
★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 的鸡肋。或许它对于【极少数】程序员有用,但对于大多数人(包括我),这玩意儿压根儿没啥好处。大伙儿还是尽量不用为妙。
AJPFX浅谈Java性能优化之finalize 函数的更多相关文章
- AJPFX浅谈Java 性能优化之字符串过滤实战
★一个简单的需求 首先描述一下需求:给定一个 String 对象,过滤掉除了数字(字符'0'到'9')以外的其它字符.要求时间开销尽可能小.过滤函数的原型如下: String filter(Strin ...
- AJPFX浅谈Java 性能优化之垃圾回收(GC)
★JVM 的内存空间 在 Java 虚拟机规范中,提及了如下几种类型的内存空间: ◇栈内存(Stack):每个线程私有的.◇堆内存(Heap):所有线程公用的.◇方法区(Method Area):有点 ...
- 浅谈java性能分析
浅谈java性能分析,效能分析 在老师强烈的要求下做了效能分析,对上次写过的词频统计的程序进行分析以及改进. 对于效能分析:我个人很浅显的认为就是程序的运行效率,代码的执行效率等等. java做性能测 ...
- 浅谈Oracle 性能优化
基于大型Oracle数据库应用开发已有6个年头了,经历了从最初零数据演变到目前上亿级的数据存储.在这个经历中,遇到各种各样的性能问题及各种性能优化. 在这里主要给大家分享一下数据库性能优化的一些方法和 ...
- 开发高性能的MongoDB应用—浅谈MongoDB性能优化(转)
出处:http://www.cnblogs.com/mokafamily/p/4102829.html 性能与用户量 “如何能让软件拥有更高的性能?”,我想这是一个大部分开发者都思考过的问题.性能往往 ...
- 开发高性能的MongoDB应用—浅谈MongoDB性能优化
关联文章索引: 大数据时代的数据存储,非关系型数据库MongoDB 性能与用户量 “如何能让软件拥有更高的性能?”,我想这是一个大部分开发者都思考过的问题.性能往往决定了一个软件的质量,如果你开发的是 ...
- 浅谈前端性能优化(二)——对HTTP传输进行压缩
1.前端性能优化的一点: 对js.css.图片等进行压缩,尽可能减小文件的大小,减少文件下载的时间,从而减少网页响应的时间. 2.前端性能优化的另一点: 对HTTP传输进行压缩,即在js,css.图片 ...
- 浅谈前端性能优化(PC版)
前端的性能优化是一个很宽泛的概念,最终目的都是为了提升用户体验,改善页面性能.面试的时候经常会遇到问谈谈性能优化的手段,这个我分几大部分来概述,具体细节需要自己再针对性的去搜索,只是提供一个索引(太多 ...
- AJPFX谈Java 性能优化之基本类型 vs 引用类型
★名词定义 先明确一下什么是“基本类型”,什么是“引用类型”. 简单地说,所谓基本类型就是 Java 语言中如下的8种内置类型: booleancharbyteshortintlongfloatdou ...
随机推荐
- iOS中区分照片的来源
原理就是通过枚举出每个assets group,然后取得group property,group property是个整数,对应头文件中的一些枚举值.用这个可以判断照片是从哪来的(相机胶卷.照片流.相 ...
- CentOS 7.2 安装Gerrit 2.14.6
1.环境 本文使用VMWare虚拟机进行实验. 2核CPU,4GB内存,20GB硬盘,IP:192.168.159.131 CentOS 7.2最小安装(CentOS-7-x86_64-Minimal ...
- 项目中Redis分库
Redis中有16个库 默认第0个库 配置库的设置: 不同的库 key可以重复哈 公司的多个不同分布式项目,但是只有一个redis时候,以项目方式区分不同的库 每个项目连接相同 但是库不同
- SQL查询速度
查询速度 https://www.cnblogs.com/ZaraNet/p/9558272.html 影响你的查询速度的原因是什么? 网速不给力,不稳定. 服务器内存不够,或者SQL 被分配的内存不 ...
- 【BZOJ 3884】 上帝与集合的正确用法
[题目链接] 点击打开链接 [算法] 通过欧拉拓展定理,列出递推公式 [代码] #include<bits/stdc++.h> using namespace std; typedef l ...
- bzoj 4260 REBXOR —— Trie树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4260 用 Trie 树可以找出前缀异或的最大值和后缀异或的最大值,拼起来即可: 注意要先加入 ...
- 详述IntelliJ IDEA插件的安装及使用方法(图解)
intellij idea是一款非常优秀的软件开发工具,它拥有这强大的插件体系,可以帮助开发者完成很多重量级的功能.今天,我们来学习一下如何安装和卸载intellij idea的插件. Intelli ...
- UVaLive 6591 && Gym 100299L Bus (水题)
题意:略. 析:不解释,水题. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include < ...
- ORACLE PL/SQL 实例精解之第六章 迭代控制之一
6.1 简单循环 简单循环,就想其名称一张,是一种最基本循环.简单循环具有如下结构 LOOP STATEMENT 1; STATEMENT 2; ... STATEMENT N; END LOOP; ...
- 洛谷 - P2578 - 九数码游戏 - bfs
https://www.luogu.org/problemnew/show/P2578 一个挺搞的东西,用康托展开做记忆化搜索可以少一个log的查询. #include <bits/stdc++ ...