• 技术文章 >Java >java教程

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

    长期闲置长期闲置2022-07-28 15:31:03转载86
    本篇文章给大家带来了关于java的相关知识,主要介绍了Java之对象销毁和finalize方法的使用,具有很好的参考价值,下面一起来看一下,希望对大家有帮助。

    推荐学习:《java视频教程

    对象的销毁

    在C++中析构方法用于释放资源并且销毁对象本身。

    在Java中,由于GC的存在,我们不需要手动回收内存,这大大减少了工作量,也提高了程序的安全性。但是Java也确实存在一个类似于C++中析构的函数。

    finalize方法

    重载该方法,用于在类被GC回收的时候执行一些操作。

    下面是一个类实现finalize的示例。

    Aoo类具有一个int 一个String属性,重载了toString并且在构造其中打印这个对象及其创建时间,在finalize中打印这个对象及调用时间。

    Aoo类

    public class Aoo {
           private int id;
           private String name;
    
           public Aoo(){
                  this(0, null);
           }
    
           public Aoo(int id, String name){
                  this.id = id;
                  this.name = name;
                  System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
           }
            /*
            * 省略get/set/toString
            */
           protected void finalize() throws Throwable{
                  super.finalize();
                  System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
           }
    }

    首先,一个简单的测试

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  Aoo a = new Aoo(1, "a");
                  a = null;
                  System.gc()
                  Thread.sleep(2000);
                  System.exit(0);
           }
    }

    打印结果:

    id:1 name:a now create:1497547723036
    id:1 name:anow finalize:1497547724059

    GC对对象的回收

    这里手动调用了GC来清理内存,而如果将其注释掉System.gc();,打印结果是这样的:

    id:1 name:a now create:1497547846923

    也就是说,在没有特意调用GC的情况下,finalize方法根本没有被调用,也就是说这个对象根本没有被主动回收。

    和想象中的不同,GC的运行方式是惰性的,也就是说,在内存没有一处的情况下,GC不会去主动回收对象,为了验证这个想法,我创建了一个线程,用于不断的消耗内存,并且不主动调用GC。

    ThreadA类

    public class ThreadA implements Runnable{
           public void run() {
                  List<Integer> list = new ArrayList<Integer>();
                  int i = 0;
                  while(true){
                         list.add(i);
                         i++;
                  }
           }
    }

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  Aoo a = new Aoo(1, "a");
                  a = null;
                  ThreadA ta = new ThreadA();
                  Thread t = new Thread(ta);
                  t.start();
                  Thread.sleep(2000);
                  System.exit(0);
           }
    }

    打印结果:

    id:1 name:a now create:1497548135268
    id:1 name:anow finalize:1497548135386

    这一次尽管没有手动调用GC,但是finalize方法仍然运行了,也就是说,只有在内存被消耗、需要GC出面清理内存的时候,GC才会运行。

    这样的finalize方法确实不靠谱,连能不能被调用都不一定,更不用说完成什么特定的操作了,如果需要关流等回收资源,不如手动调用一个方法,或者在final块中统一释放资源。

    在finalize方法中,是否重新给自己指定一个引用来避免被GC回收?

    尝试在finalize方法中重新引用来让GC无法回收

    修改后的Aoo如下

    public class Aoo {
           public static Aoo SAVE = null;
           private int id;
           private String name;
    
           public Aoo(){
                  this(0, null);
           }
    
           public Aoo(int id, String name){
                  this.id = id;
                  this.name = name;
                  System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
           }  
           /*
            * 省略get/set/toString
            */
           protected void finalize() throws Throwable{
                  super.finalize();
                  System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
                  SAVE = this;
           }
    }

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  Aoo.SAVE = new Aoo(1, "a");
                  Aoo.SAVE = null;
                  System.gc();
                  Thread.sleep(500);
                  System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );              
                  System.exit(0);             
           }
    }

    打印结果:

    id:1 name:a now create:1497551409195
    id:1 name:anow finalize:1497551409201
    a is alive

    这里看出,Aoo.SAVE对象确实“复活了”,不过这样的操作是有限制的,如果故技重施不会再一次“复活”该对象。

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  Aoo.SAVE = new Aoo(1, "a");
                  Aoo.SAVE = null;
                  System.gc();
                  Thread.sleep(500);
                  System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );
    
                  Aoo.SAVE = null;
                  System.gc();
                  Thread.sleep(500);
                  System.out.println(Aoo.SAVE == null? "a is dead" : "a is alive" );
    
                  System.exit(0);          
           }
    }

    打印结果:

    id:1 name:a now create:1497551587715
    id:1 name:anow finalize:1497551587721
    a is alive
    a is dead

    这里注意到,两次的操作是相同的,而finalize方法只会被系统调用一次。

    如果finalze方法中出现死循环会发生什么?

    Aoo类

    public class Aoo {
           private int id;
           private String name;
    
           public Aoo(){
                  this(0, null);
           }
    
           public Aoo(int id, String name){
                  this.id = id;
                  this.name = name;
                  System.out.println(this.toString() + " now create:" + System.currentTimeMillis());
           }
           /*
            * 省略get/set/toString
            */
           protected void finalize() throws Throwable{
                  super.finalize();
                  while(true){
                         System.out.println(this.toString() + "now finalize:" + System.currentTimeMillis());
                         Thread.sleep(100);
                  }
           }
    }

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  Aoo a1 = new Aoo(1 , "a1");
                  Aoo a2 = new Aoo(2 , "a2");
                  a1 = null;
                  a2 = null;
                  ThreadA ta = new ThreadA();
                  Thread t = new Thread(ta);
                  t.start();
                  Thread.sleep(5000);
    
                  System.exit(0);
           }
    }

    打印结果:

    id:1 name:a1 now create:1497552024252
    id:2 name:a2 now create:1497552024252
    id:1 name:a1now finalize:1497552024373
    id:1 name:a1now finalize:1497552024503
    id:1 name:a1now finalize:1497552026848
    id:1 name:a1now finalize:1497552028960
    id:1 name:a1now finalize:1497552032363

    结果是随机的,有时候是执行的a1的finalize,有的时候执行的是a2的。

    这个结果说明了两点:

    1.finalze方法在的线程优先级很低,时间间隔相当的不确定并且明显大于100毫秒。

    2.这个死循环导致了别的对象的finalize方法无法执行。

    如果对象的创建出现这种死循环,会不会导致对象无法销毁进而导致内存溢出?

    我们大量创建Aoo对象,并且等待GC自己回收内存。

    为了直观的观看finalize方法的调用情况,删除掉了Aoo对象初始化的时候的打印代码。

    main方法

    public class FinalizeTest {
           public static void main(String[] args) throws Exception {
                  int i = 1;
                  while(true){
                         Aoo a = new Aoo(i , "a" + i);
                         i++;
                  }
           }
    }

    让程序执行了约两分钟,然后手动终止,查看输出

    1497554225913
    id:269614 name:a269614now finalize:1497554226151
    id:269614 name:a269614now finalize:1497554227635
    id:269614 name:a269614now finalize:1497554227735
    id:269614 name:a269614now finalize:1497554227836
    id:269614 name:a269614now finalize:1497554229586
    id:269614 name:a269614now finalize:1497554229686
    id:269614 name:a269614now finalize:1497554229951
    id:269614 name:a269614now finalize:1497554230051
    id:269614 name:a269614now finalize:1497554230152
    id:269614 name:a269614now finalize:1497554233699
    id:269614 name:a269614now finalize:1497554233800
    id:269614 name:a269614now finalize:1497554233900
    id:269614 name:a269614now finalize:1497554234308
    id:269614 name:a269614now finalize:1497554234408
    id:269614 name:a269614now finalize:1497554234508
    id:269614 name:a269614now finalize:1497554235053
    id:269614 name:a269614now finalize:1497554235153
    id:269614 name:a269614now finalize:1497554235253
    id:269614 name:a269614now finalize:1497554235823
    id:269614 name:a269614now finalize:1497554235923
    id:269614 name:a269614now finalize:1497554236023
    id:269614 name:a269614now finalize:1497554240324
    id:269614 name:a269614now finalize:1497554240424
    id:269614 name:a269614now finalize:1497554240525
    id:269614 name:a269614now finalize:1497554241146
    id:269614 name:a269614now finalize:1497554241247
    id:269614 name:a269614now finalize:1497554241347
    id:269614 name:a269614now finalize:1497554241448
    id:269614 name:a269614now finalize:1497554242020
    id:269614 name:a269614now finalize:1497554242120
    id:269614 name:a269614now finalize:1497554242220
    id:269614 name:a269614now finalize:1497554242321
    id:269614 name:a269614now finalize:1497554242421
    id:269614 name:a269614now finalize:1497554242521
    id:269614 name:a269614now finalize:1497554248367
    id:269614 name:a269614now finalize:1497554248467
    id:269614 name:a269614now finalize:1497554248567
    id:269614 name:a269614now finalize:1497554248667
    id:269614 name:a269614now finalize:1497554249534
    id:269614 name:a269614now finalize:1497554249634
    id:269614 name:a269614now finalize:1497554249734
    id:269614 name:a269614now finalize:1497554249835
    id:269614 name:a269614now finalize:1497554255954
    id:269614 name:a269614now finalize:1497554256055
    id:269614 name:a269614now finalize:1497554256155
    id:269614 name:a269614now finalize:1497554256255
    id:269614 name:a269614now finalize:1497554256356
    id:269614 name:a269614now finalize:1497554257285
    id:269614 name:a269614now finalize:1497554257386
    id:269614 name:a269614now finalize:1497554257486
    id:269614 name:a269614now finalize:1497554257586
    id:269614 name:a269614now finalize:1497554257686
    id:269614 name:a269614now finalize:1497554268652
    id:269614 name:a269614now finalize:1497554268753
    id:269614 name:a269614now finalize:1497554268853
    id:269614 name:a269614now finalize:1497554268953
    id:269614 name:a269614now finalize:1497554269054
    id:269614 name:a269614now finalize:1497554269154
    id:269614 name:a269614now finalize:1497554277474
    id:269614 name:a269614now finalize:1497554292852
    id:269614 name:a269614now finalize:1497554301062

    可以发现两个情况:

    1.只有一个对象的finalize方法被执行了,也就是说这个死循环的finalize方法阻止了其他对象执行finalize方法

    2.程序执行很快的一段时间后,finalize方法就开始执行,但是随着内存消耗的不断增加,finalize方法被执行的次数也就越来越少。至于为什么这样,我不知道= =#

    总结

    至此,我尝试了finalize方法的一些用法和特殊情况。可以看出,GC调用finalize方法存在巨大的不确定性,确实很不靠谱,不过通过这个方法,了解了一些关于GC的知识,也让我明白,虽然Java语言虽然具有高度的一致性等特点使之很容易上手,但是要做到对Java的精通,路还很远呢~~

    推荐学习:《java视频教程

    以上就是Java之对象销毁和finalize方法的使用的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:脚本之家,如有侵犯,请联系admin@php.cn删除
    专题推荐:java
    上一篇:java实例解析之1M图片压缩优化到100kb 下一篇:实例介绍基于Java实现一个复杂关系表达式过滤器
    VIP课程(WEB全栈开发)

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• Java中Map接口的使用以及面试知识点总结• JavaScript中switch的四种写法示例• 详细解析java词法分析器DDL递归应用• 深入理解JavaScript内存管理和GC算法• java实例解析之1M图片压缩优化到100kb
    1/1

    PHP中文网