finalize

前言

今天又看了下java编程思想,听实习期间“老大”的,这本书需要看三年,这也是我买这本书的第三年了(没有完整的看完过),每年都会看下,但是每次看感觉都不一样,第一年看是头大,第二年看是勉强能看懂一部分,第三年看会带着工作中的实践去思考,渐入佳境,时间过的太快了我还是没看完,今年必须得看完了,明年再看一遍就不再看了。

今天看到finalize有一个实例一直搞不出来,问了下我们公司得架构师,架构师说我怎么还在看这个,说我方向可能错了搞得太深了,应该去看框架源码、jvm内核啥得,我问的问题实际工作遇到太少了。但是我总觉得连java本身一些基础的知识都不了解(这里只是了解并没有深入)的比较全面会阻碍我未来思考问题的广度,源码我也是看的,但是是遇到问题或者感兴趣才去看,至于jvm也一直在看也是断断续续的,这可能和我自己的性格也是有关系的,总是想知道的比较清楚。

主题

finalize在实际工作中确实没有遇到过,但是还是要先了解下,书上是说这个是用来做一些除了new出来对象的清除,比如一些通过本地方法开辟出来的内存消耗,但是调用这个方法是对象产生了gc回收的时候,等下一次才会真正回收该对象,同时也可以做一些gc回收之前对对象的检验,比如根据对象的字段值检验下对象是否能被回收,不能回收可以打印日志或者抛出异常等。下面看例子

  static class Person {
        boolean checkedOut = false;

        Person(boolean checkedOut) {
            this.checkedOut = checkedOut;
        }

        void checkIn() {
            checkedOut = false;
        }

        @Override
        protected void finalize() throws Throwable {
            if (checkedOut) {
                System.out.println("Error:checked out");
            }
            super.finalize();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Person p1 = new Person(true);
        p1.checkIn();
        Person p2 = new Person(true);
          
        System.gc();
    }

执行结果

"C:\Program Files\Java\jdk1.8.0_60\bin\java" ...

Process finished with exit code 0

并没有打印出来

后来折腾了下,改为:

 static class Person {
        boolean checkedOut = false;

        Person(boolean checkedOut) {
            this.checkedOut = checkedOut;
        }

        void checkIn() {
            checkedOut = false;
        }

        @Override
        protected void finalize() throws Throwable {
            if (checkedOut) {
                System.out.println("Error:checked out");
            }
            super.finalize();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread() {
            @Override
            public void run() {
                Person p1 = new Person(true);
                p1.checkIn();
                Person p2 = new Person(true);

            }
        };
        t1.start();
        Thread.sleep(10);
        System.gc();
        Thread.sleep(10);
    }

就可以了

"C:\Program Files\Java\jdk1.8.0_60\bin\java" ...
Error:checked out

Process finished with exit code 0

解释下改动点:

  • 1:new对象和发送消息用开启了新的线程,不和gc回收都放在主线程是因为都在本方法中虚拟机怕后面还会使用到对象。
  • 2:第一个Thread.sleep(10),因为开启新线程了,需要等new对象和发送消息完成了才进行gc。
  • 3:第二个Thread.sleep(10),因为gc后面没有其他要执行的了,主线程都已经结束看不到执行finalize的打印。

具体过程

判定一个对象objA是否可回收,至少经历两次标记过程:

  1. 如果对象objA到GC Roots没有引用链,则进行第一次标记。
  2. 进行筛选,判断对象是否有必要执行finalize()方法。
    1.- 如果对象objA没有重写finalize()方法,或者finalize()方法已经被虚拟机调用过,则虚拟机视为“没必要执行”,objA被判定为不可触及。
    2.- 如果对象objA重写了finalize()方法,且还未执行过,那么objA会被插入到F-Queue队列中,由虚拟机自动创建的、低优先级的Finalizer线程触发其finalize()方法。
    3.- finalize()方法是对象逃脱死亡对象的最后机会,稍后GC会对F-Queue队列中的对象进行第二次标记。如果objA在finalize()方法中与引用链上的任何对象建立联系,那么在第二次标记的时候会被移出“即将回收” 集合。之后,对象会再次出现没有引用存在的情况。在这个情况下,finalize方法不会被再次调用,对象会直接变成不可触及的状态,也就是说, 一个对象的finalize方法只会被调用一次。

开始并没有反应过来还是因为对jvm的执行过程不够理解,这也充分说明了基础可以不牢固,同样可以写业务代码,但是有一天发生了一些不可解释的问题时总归结于“神学”或者重启电脑,哈哈哈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值