java9之前finalizer,java9使用cleaner代替了finalizer。相比finalizer,cleaner(它存在于一个独立类Cleaner中,需要时候注入到对应类中即可)不会污染API而且cleaner有类库可以控制它的线程(它两都在后台线程中执行)。

避免使用的原因:

  1. 行为的不稳定性

    • 它两都不能保证及时的执行,从方法可达到(对象被置空了)开始到最终的执行,时间是任意长的。所以千万不要使用他们来更新重要的持久状态,如释放流资源、分布式锁等。

    • System.gc和System.runFinalization这两个方法会增加finalizer和cleaner被执行的机会,但是不保证一定会执行。唯一能保证它两会被执行的两个方法(System.runFinalizersOnExit和Runtime.runFinalizersOnExit)有致命的缺陷,已经被废除很久了。

  1. 移植性问题

    不同的JVM堆垃圾回收的算法不同,如果程序依赖finalizer或者cleaner被执行的时间点,那么程序的表现可能截然不同

  2. 性能问题

    finalizer和cleaner有一个非常严重的性能损耗。

  3. 安全问题

    • finalizer中如果出现异常会导致线程终止,但是不会打印线程轨迹甚至警告都不会打印出来,而且使正在销毁的对象处于破坏状态,另一个线程如果使用这个破坏状态的对象会出现行为的不确定性。cleaner没有这个问题。

    • finalizer攻击:利于finalizer方法,构建出恶意子类对象,非法调用父类方法。final类不会被构建恶意子类,所以不会遭到finalizer攻击。对于非final类,重写一个空的finalizer方法并用final修饰来防止finalizer攻击。

      //构建对象使用后不能再次被实例化
      public class Demo{
         private boolean flag = true;
         //防止实例化
         public  Demo() {
             if (flag){
                 throw new RuntimeException("不准许再次创建对象");
            }
        }
         public  void say() {
             System.out.println("DemoUtils.say");
        }
      }
      //构建非法子类
      class Demo2 extends Demo{
         public Demo2(){}
         //构建finalizer攻击
         @Override
         protected void finalize() throws Throwable {
             //会调用父类方法
             this.say();
             System.exit(0);
        }
         public static void main(String[] args) throws InterruptedException {
             try {
                 //创建子类对象必然会调用父类构造,所以会发生异常
                 //但是在gc中还是执行了父类的方法
                 Demo demo = new Demo2();
                 demo.say();
            } catch (Exception e) {
                 System.out.println(e);
            }
             System.gc();
             //给垃圾回收提供时间
             Thread.sleep(5000);
        }
      }
      //运行结果
      java.lang.RuntimeException: 不准许再次创建对象
      DemoUtils.say

两个用处:

  1. 安全网

    当资源的所有者忘记使用close方法的时候,finalizer和cleaner可以充当安全网,虽然不能保证及时的释放资源,但是迟一点释放总比永远不释放要好。要使用这样的安全网就要认证的考虑清除是否值得付出这样的代价。所以Java一些AutoCloseable实现中都添加了安全网。

    这是FileOutputStream的源码

  2. 回收本地对等体对象

    本地对等体:java操作native方法其实是委托给一个本地对等体对象,使用完成后java对象会被GC回收,但是这个对等体对象不是java对象不会被会GC回收。如果这个对象性能可以接受,而且没有需要及时释放的资源那么就可以使用finalizer或者cleaner进行回收了。但是如果这个对等体性能无法接受且拥有必须被及时终止的资源,那么就需要提供一个close方法了。

最新文章

  1. 2016福州大学软件工程第二次团队作业——预则立&&他山之石成绩统计
  2. JavaScript 输出
  3. filter,orderBy等过滤器
  4. atitit.短信 验证码  破解  v3 p34  识别 绕过 系统方案规划----业务相关方案 手机验证码  .doc
  5. nginx location匹配规则
  6. 单元测试_JUnit4的应用与实践
  7. JavaScript中判断为整数的多种方式
  8. POJ 1666
  9. 【python】开始python之旅
  10. What Influences Method Call Performance in Java?--reference
  11. Apache【第一篇】安装
  12. ARC - strong和weak指针
  13. 字符串转换为float<1>
  14. 如何在苹果手机上安装自制的AD证书
  15. 纯 CSS 绘制三角形(各种角度)
  16. 循环语句(for,while,do……while),方法概述
  17. mysql循环插入数据、生成随机数及CONCAT函数
  18. 牛客练习赛A 【BFS】
  19. 单例模式和JDBC
  20. iOS Runloop理解

热门文章

  1. uni-app in action
  2. Azure 信用卡扣款 1 美元 & Azure 中国客服
  3. 微信公众号 bug
  4. SHON WEBB:太怀念过去的人,往往走不远
  5. 1053 Path of Equal Weight——PAT甲级真题
  6. es6 快速入门 系列 —— 变量声明:let和const
  7. 后端程序员之路 36、Apache Kafka
  8. 大话Spark(5)-三图详述Spark Standalone/Client/Cluster运行模式
  9. double型数据的输入和输出--%f和%lf
  10. 一文读懂Java动态代理