Java禁止使用finalize方法

什么是finalize方法

finalize()方法被定义在Java.lang.Object类中,意味着所有的类都可以重载这个方法。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()里面访问某些数据的时候,还得时刻留心线程安全的问题。

总结

以上所述是小编给大家介绍的Java禁止使用finalize方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 简单理解Java的垃圾回收机制与finalize方法的作用

    垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法(你可以 写程序验证这个结论),一般的纯Java编写的Class不需要重新覆盖这个方法,因为Object已经实现了一个默认的,除非我们要实现特殊的功能(这 里面涉及到很多东西,比如对象空间树等内容). 不过用Java以外的代码编写的Class(比如JNI,C++的new方法分配的内存),垃圾回收器并不能对这些部分进行正确的回收,这时就需要我们覆盖默认的方法来实现对这部分内存的正确释放和回收(比如C++需要delete). 总之,f

  • 详谈Java中Object类中的方法以及finalize函数作用

    Object是所有类的父类,任何类都默认继承Object. 一.Object类中的方法 1.clone方法 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法. 2.getClass方法 final方法,获得运行时类型. 3.toString方法 该方法

  • Java禁止使用finalize方法

    什么是finalize方法 finalize()方法被定义在Java.lang.Object类中,意味着所有的类都可以重载这个方法.java垃圾回收器只之道释放那些经由new分配的内存,所以如果你的对象并非通过new获得的内存,那么垃圾回收器就不知道如何释放该对象的内存了. 为了应对这种情况,java允许在类中重载java.lang.Object类中的finalize()方法. 它的工作原理:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动

  • Java中覆盖finalize()方法实例代码

    本文研究的主要是Java中关于覆盖finalize()方法的一次尝试,具体实现如下. 测试代码 package com.alioo.gc; /** * 执行结果: * */ public class FinalizeEscapeGC{ public static FinalizeEscapeGC instance=null; public void isAlive(){ System.out.println("yes,i am still alive"); } @Override pr

  • Java垃圾回收机制的finalize方法实例分析

    本文实例讲述了Java垃圾回收机制的finalize方法.分享给大家供大家参考,具体如下: 一 点睛 finalize方法有如下四个特点: 永远不要主动调用某个对象的finalize方法,该方法应交给垃圾回收机制调用. finalize方法的何时被调用,是否被调用具有不确定性.不要把finalize方法当成一定会被执行的方法. 当JVM执行可恢复对象的finalize方法时,可能使该对象或系统中其他对象重新变成可达状态. 当JVM执行finalize方法时出现了异常,垃圾回收机制不会报告异常,程

  • Java之对象销毁和finalize方法的使用

    目录 对象的销毁 finalize方法 GC对对象的回收 在finalize方法中,是否重新给自己指定一个引用来避免被GC回收? 如果finalze方法中出现死循环会发生什么? 如果对象的创建出现这种死循环,会不会导致对象无法销毁进而导致内存溢出? 总结 对象的销毁 在C++中析构方法用于释放资源并且销毁对象本身. 在Java中,由于GC的存在,我们不需要手动回收内存,这大大减少了工作量,也提高了程序的安全性.但是Java也确实存在一个类似于C++中析构的函数. finalize方法 重载该方法

  • 深入了解Java中finalize方法的作用和底层原理

    目录 finalize方法是什么 finalize方法与C++的析构函数的区别 finalize方法合适清理的对象 可以触发finalize执行的方法 finalize实现对象再生问题 finalize的执行过程(生命周期) 对象对于finalize方法的两种状态 终结状态空间 可达状态空间 代码示例 对象复活 覆盖finalize方法以确保资源释放 finalize方法是什么 finalize方法是Object的protected方法,Object的子类们可以覆盖该方法以实现资源清理工作,GC

  • Java垃圾回收finalize()作用详解

    finalize 方法使用案例 package test; class TestGC { private String str = "hello"; TestGC(String str) { this.str = str; } public void finalize() { System.out.println(str); } } public class Hello { /** * @param args */ public static void main(String[] ar

  • 详解Java面向对象编程中方法的使用

    一个 Java 方法是为了执行某个操作的一些语句的组合.举个例子来说,当你调用 System.out.println 方法时,系统实际上会执行很多语句才能在控制台上输出信息. 现在你将学习怎么创建你自己的方法,他们可以有返回值也可以没有返回值,可以有参数,也可以没有参数,重载方法要使用相同的方法名称,并在程序设计中利用抽象的方法. 创建方法 我们用下面的例子来解释方法的语法: public static int funcName(int a, int b) { // body } 在这里 pub

  • 浅谈Java中的桥接方法与泛型的逆变和协变

    目录 1. 泛型的协变 1.1 泛型协变的使用 1.2 泛型协变存在的问题 1.2.1 Java当中桥接方法的来由 1.2.2 为什么泛型协变时,不允许添加元素呢 1.2.3 从Java字节码的角度去看桥接方法 2. 泛型逆变 2.1 泛型逆变的使用 2.2 泛型逆变会有什么问题 3.协变与逆变-PECS原则 泛型的协变和逆变是什么?对应于Java当中,协变对应的就是<? extends XXX>,而逆变对应的就是<? super XXX>. 1. 泛型的协变 1.1 泛型协变的使

  • Java单例模式实现静态内部类方法示例

    Singleton是众多设计模式中最容易理解的一种,也是众多设计模式中较为重要的一种设计模式.接下来我们看看具体介绍. Singleton模式实现的重点在于将构造函数私有化(private),并通过提供静态公有函数(public synchronized static xxx getInstance)来获取定义在类中的静态私有成员(private static xxx instance),通过一个简单的判断静态实例是否为空来控制这个类只能够new一次,即控制了一个类只能有单个实例,一般的实现如下

随机推荐