· 编程思想  · 4 min read

关于垃圾回收的机制与机理之孤岛垃圾

对象成为垃圾的条件

  1. 对于非线程对象来说 当所有的活动线程都不可能访问到这对象时,变成垃圾
  2. 对于线程对象来说 除了上一条之外,还要求吃线程本身已经死亡或者还处于新建状态,才是垃圾,才能被回收

千万不要片面的认为“没有引用指向的对象就是垃圾,有引用指向的就不是垃圾”是对的孤岛垃圾就是个反驳的例子

class Island{
    public Island brother;
}

  //运行下面代码片段
    Island il = new Island();
    Island i2 = new Island();
    Island i3 = new Island();

    il.brother = i2;
    i2.brother = i3;
    i3.brother = i1;

    i1 = null;
    i2 = null;
    i3 = null;

    // 这样 三个对象循环指向  但他们形成了孤岛 所以已经成为垃圾

垃圾回收非线程的例子

class Island{
    public Island brother;
    String name;
    public Island(){
    }
    public Island(String name){
        this.name = name;
    }
    public void finalize(){
        System.out.println(this.name + "对象成为垃圾,被收集");
    }
    public void testIsland(){
        Island i1 = new Island("孤岛中的 O1");
        Island i2 = new Island("孤岛中的 O2");
        Island i3 = new Island("孤岛中的 O3");

        i1.brother = i2;
        i2.brother = i3;
        i3.brother = i1;

        i1 = null;
        i2 = null;
        i3 = null;
        // 这样 三个对象循环指向  但他们形成了孤岛 所以已经成为垃圾

        System.gc();//可以看到 三个对象很快被收集,但程序过了10s才结束
        try{
            Thread.sleep(10000);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

public class Test{
    public static void main(String[] args){
        new Island().testIsland();
    }
}

线程垃圾例子

public class Test{
    public static void main(String[] args){
//      new Island().testIsland();
        new RubbishThread().testRT();
    }
}

class RubbishThread extends Thread{

    RubbishThread brother;
    String rtName;

    public RubbishThread(){

    }

    public RubbishThread(String name){
        this.rtName = name;
    }

    public void run(){
        System.out.println(this.rtName + "线程启动了");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(this.rtName + "线程结束");
    }

    public void finalize(){
        System.out.println(this.rtName + "成为垃圾被收集");
    }

    public void testRT(){
        RubbishThread rt1 = new RubbishThread("孤岛中的rt1线程");
        RubbishThread rt2 = new RubbishThread("孤岛中的rt2线程");
        RubbishThread rt3 = new RubbishThread("孤岛中的rt3线程");

        rt1.brother = rt2;
        rt2.brother = rt3;
        rt3.brother = rt1;

        rt1.start();

        rt1 = null;
        rt2 = null;
        rt3 = null;

        System.out.println("---------对无引用但活着的线程进行垃圾收集--------------");
        System.gc();

        try{
            Thread.sleep(2000);//主线程休眠2s
        }catch(Exception e){
            e.printStackTrace();
        }

        System.out.println("---------对无引用死亡的线程进行垃圾收集--------------");
        System.gc();

        try{
            Thread.sleep(1000);//主线程休眠1s
        }catch(Exception e){
            e.printStackTrace();
        }
    }
// 执行结果
//  ---------对无引用但活着的线程进行垃圾收集--------------
//  孤岛中的rt1线程线程启动了
//  孤岛中的rt1线程线程结束
//  ---------对无引用死亡的线程进行垃圾收集--------------
//  孤岛中的rt3线程成为垃圾被收集
//  孤岛中的rt2线程成为垃圾被收集
//  孤岛中的rt1线程成为垃圾被收集

//解释:执行第一次垃圾收集由于线程rt1还没有死亡,虽然形成了孤岛垃圾
//      但其中的对象可以被活动的进程访问到,整个孤岛不是垃圾
//      执行第二次垃圾收集时rt1已经死亡 整个孤岛成为垃圾,3个线程都被收集
//      没有启动的线程与死亡的线程一样,只要满足普通对象成为垃圾的条件就是垃圾

}
Share:
Back to Blog