禁止使用finalize方法
Don´t use Finalizers, mainly because are unpredictable and we don´t know when will be executed, "don't try to be smarter than the JVM"
什么是finalize方法
finalize()方法被定义在Java.lang.Object类中,意味着所有的类都可以重载这个方法。finalize方法为什么时protected。
java垃圾回收器只之道释放那些经由new分配的内存,所以如果你的对象并非通过new获得的内存,那么垃圾回收器就不知道如何释放该对象的内存了。
为了应对这种情况,java允许在类中重载java.lang.Object类中的finalize()方法。
它的工作原理:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
finalize函数的调用机制
java虚拟机规范并没有硬性规定垃圾回收该不该搞,以及该如何搞。所以这里提到的调用机制不能保证适合所有jvm。
何时被调用?
finalize啥时候才会被调用捏?一般来说,要等到JVM开始进行垃圾回收的时候,它才有可能被调用。而JVM进行垃圾回收的时间点是非常不确定的,依赖于各种运行时的环境因素。正是由于finalize函数调用时间点的不确定,导致了后面提到的某些缺点。
谁来调用?
常见的JVM会通过GC的垃圾回收线程来进行finalize函数的调用。由于垃圾回收线程比较重要(人家好歹也是JVM的一个组成部分嘛),为了防止finalize函数抛出的异常影响到垃圾回收线程的运作,垃圾回收线程会在调用每一个finalize函数时进行try catch,如果捕获到异常,就直接丢弃,然后接着处理下一个失效对象的finalize函数。
为什么禁止使用finalize()
1.调用时间不确定---有资源浪费的风险
前面已经介绍了调用机制。同学们应该认清“finalize的调用时机是很不确定的”这样一个事实。所以,假如你把某些稀缺资源放到finalize()中释放,可能会导致该稀缺资源等上很久很久很久以后才被释放。这可是资源的浪费啊!另外,某些类对象所携带的资源(比如某些JDBC的类)可能本身就很耗费内存,这些资源的延迟释放会造成很大的性能问题。
2.可能不被调用----有资源泄露的风险
很多同学以为finalize()总是会被调用,其实不然。在某些情况下,finalize()压根儿不被调用。比如在JVM退出的当口,内存中那些对象的finalize函数可能就不会被调用了。
估计有同学在打“runFinalizersOnExit”的主意,来确保所有的finalize在JVM退出前被调用。很可惜也很遗憾,该方法从JDK 1.2开始,就已经被废弃了。即使该方法不被废弃,也是有很大的线程安全隐患滴! 从上述可以看出,一旦你依赖finalize()来帮你释放资源,那可是很不妙啊(有资源泄漏的危险)!很多时候,资源泄露导致的性能问题更加严重,万万不可小看。
3.对象可能在finalize函数调用时复活
本来,只有当某个对象已经失效(没有引用),垃圾回收器才会调用该对象的finalize函数。但是,万一碰上某个变态的程序员,在finalize()函数内部再把对象自身的引用(也就是this)重新保存在某处,也就相当于把自己复活了(因为这个对象重新有了引用,不再处于失效状态)。 为了防止发生这种诡异的事情,垃圾回收器只能在每次调用完finalize()之后再次去检查该对象是否还处于失效状态。这无形中又增加了JVM的开销。 随便提一下。由于JDK的文档中规定了,JVM对于每一个类对象实例最多只会调用一次finalize()。所以,对于那些诈尸的实例,当它们真正死亡时,finalize()反而不会被调用了。这看起来是不是很奇怪?
4.要记得自己做异常捕获
刚才在介绍finalize()调用机制时提到,一旦有异常抛出到finalize函数外面,会被垃圾回收线程捕获并丢弃。也就是说,异常被忽略掉了(异常被忽略的危害,“这里”有提到)。为了防止这种事儿,凡是finalize()中有可能抛出异常的代码,你都得写上try catch语句,自己进行捕获。
5.小心线程安全
由于调用finalize()的是垃圾回收线程,和你自己代码的线程不是同一个线程;甚至不同对象的finalize()可能会被不同的垃圾回收线程调用(比如使用“并行收集器”的时候)。所以,当你在finalize()里面访问某些数据的时候,还得时刻留心线程安全的问题。
reference
2014-11-13 20:01:32
Brave,Happy,Thanksgiving !
原文地址:http://leihuang.org/2014/11/13/Avoid-Finalizers/
禁止使用finalize方法的更多相关文章
- [java]final关键字、finally关键字与finalize()方法
final关键字: final关键字通常指的是“无法改变的”,使用“无法改变”这样修饰可能出于两个原因:设计或者效率. final可以修饰变量.方法和类. 一.final变量 一个既是static又是 ...
- C#中Finalize方法的问题
ninputer在关于"值类型的Finalize不会被调用"中(http://blog.joycode.com/lijianzhong/archive/2005/01/13/429 ...
- Windows 和 Linux 下 禁止ping的方法
Windows 和Linux 下 禁止ping的方法 目的: 禁止网络上的其他主机或服务器ping自己的服务器 运行环境: Windows 03.08 linux 方法: Windows 03下: ...
- 第五节:什么导致Finalize方法被调用
Finalize方法在垃圾回收结束时被调用,下面有5种事件会导致开始垃圾回收 1.第0代已满 第0代已满,垃圾回收会自动开始.该事件是目前导致Finalize方法被调用的最常见的一种方式,因为虽 ...
- Java中finalize方法用途何在?
package thinking.in.java.demo; /* * finalize的用途何在? * *本例的终止条件是L所有的Book对象在被当做垃圾回收前都应该被签入.但是在main方法中 * ...
- Java 声明和访问控制(三) finalize方法 成员访问修饰符
finalize()方法是Object类的一个方法,在垃圾回收器执行的时候,会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源的回收,例如文件关闭等. 成员访问修饰符: 默认访问:包访问 ...
- JAVA中的finalize()方法
[转]JAVA中的finalize()方法 今天早上看Thinking in java的[第四章 初始化和清除].[ 清除:终结和垃圾回收]的时候, 看到了这个东西. 用于清理滴... 当然,这个方 ...
- Java基础--finalize()方法
原理: 一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存. 用途: 1)释放通过某种创建对象方式以外的方式为对 ...
- Java对象中的finalize()方法使用说明
我在写java程序的时候,从来没有遇见过是用Object.finalize()的时候,但是在学习Java虚拟机的垃圾回收机制时,虚拟机在进行垃圾回收时需要使用finalize()方法来进行对象清理.下 ...
随机推荐
- Ansible安装配置Nginx
一.思路 现在一台机器上编译安装好nginx.打包,然后在用ansible去下发 cd /etc/ansible 进入ansible配置文件目录 mkdir roles/{common,install ...
- MongoDB安装、配置和基本使用
一.搭建MongoDB的yum源 如果安装epel扩展源,可以安装MongoDB2.4版本 如要安装3.0版本,需要自己配置yum源,官方提供的源只支持64位系统 # vim /etc/yum.rep ...
- Java—面向对象—构造方法及相关思维导图
先构造一个Book类的代码 package org.hanqi.pn0120; public class Book { //构造方法 //1.方法名和类名一样 //2.没有返回值,不需要加void / ...
- Json数据,转换规则,
JSON数据转换,规则是遇见json 中的{},则是数组[],遇见name:value,则是'key'=>'value', 但是不带键值的数组如['xxxxxx'],json_encode后仍然 ...
- Python爬虫学习笔记——豆瓣登陆(一)
#-*- coding:utf-8 -*- import requests from bs4 import BeautifulSoup import html5lib import re import ...
- ARM体系的7种工作模式
一.ARM体系的CPU有以下7种工作模式: 用户模式(usr) 大多数程序运行于用户模式 特权模式 系统模式(sys) 运行具有特权的操作系统任务 异常模式 中断模式(irq) ...
- 查找目录下的所有文件中是否含有某个字符串 linux
查找目录下的所有文件中是否含有某个字符串 find .|xargs grep -ri "IBM" 查找目录下的所有文件中是否含有某个字符串,并且只打印出文件名 find .|xar ...
- (总结)Linux下使用rsync最快速删除海量文件的方法
昨天遇到了要在Linux下删除海量文件的情况,需要删除数十万个文件.这个是之前的程序写的日志,增长很快,而且没什么用.这个时候,我们常用的删除命令rm -fr * 就不好用了,因为要等待的时间太长.所 ...
- QQ登入(4)QQ分享-内容转载
///////////////////QQ分享///////////// public void myclick3(View v){ //shareType : SHARE_TO_QQ_TYPE_IM ...
- Unity3D 几个基本动画(控制物体移动、旋转、缩放)
Transform基本移动函数: 1.指定方向移动: //移动速度 float TranslateSpeed = 10f; //Vector3.forward 表示"向前" tra ...