JAVA 垃圾回收机制原理

这里,我不用什么理论方式讲述垃圾回收机制原理.我只通过2个简单的程序,探讨我对Java 垃圾回收机制的理解.毕竟很多东西,理论的术语可能没有直观的测试更好.

 

package cn.vicky.chapt14;


/**
 *
 * @author Vicky.H
 */
public class FinalizeTest {
    
    public static void main(String[] args) throws InterruptedException {
        Session session = new Session();
        
        Object[] arr1 = new Object[5];
        Object[] arr2 = new Object[10];
        
        System.out.println(session.hashCode());
        arr1[3] = session;
        System.out.println(arr1[3].hashCode());
        arr2[7] = session;
        System.out.println(arr2[7].hashCode());
        
        System.out.println("--------------");
    
        session = null;
        System.out.println(arr1[3].hashCode());
        System.out.println(arr2[7].hashCode());
        System.gc();
        System.out.println("第一次销毁session");
        
        System.out.println("--------------");
        arr1[3] = null;
        System.gc();
        System.out.println("第二次销毁session");
        System.out.println(arr2[7].hashCode());
        System.out.println("--------------");
        arr2[7] = null;
        System.gc();
        System.out.println("第三次销毁session.可见,当内存中的对象在Java程序没有任何一个指向的时候,"
                + "通过垃圾回收机制才能正在销毁对象.请注意,该条打印语句虽然执行顺序在System.gc()之后"
                + "被执行的,但在打印\"销毁对象\"之前已经被打印出来,表示System.gc()是异步的."
                + "它的执行不并影响主程序的执行,它将交与JVM虚拟机执行!");
        Thread.sleep(30000);
        System.out.println("总结:Java无法像C或C++那样通过free() delete 销毁对象,但Java可以通过"
                + "取消对\"对象\"的所有引用并且调用System.gc()的方式来进行销毁.");
        System.out.println("Test Over");
    }
}
class Session {
    int id;
    String name;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁对象");
        super.finalize();
    }
}


run-single:
33263331
33263331
33263331
--------------
33263331
33263331
第一次销毁session
--------------
第二次销毁session
33263331
--------------
第三次销毁session.可见,当内存中的对象在Java程序没有任何一个指向的时候,通过垃圾回收机制才能正在销毁对象.请注意,该条打印语句虽然执行顺序在System.gc()之后被执行的,但在打印"销毁对象"之前已经被打印出来,表示System.gc()是异步的.它的执行不并影响主程序的执行,它将交与JVM虚拟机执行!
销毁对象
总结:Java无法像C或C++那样通过free() delete 销毁对象,但Java可以通过取消对"对象"的所有引用并且调用System.gc()的方式来进行销毁.
Test Over

 

package cn.vicky.chapt14;

/**
 *
 * @author Vicky.H
 */
public class FinalizeTest2 {
    
    public static void sayHello1(){
        System.out.println("hello world".hashCode());
    }

    public static void sayHello2(){
        System.out.println("hello world".hashCode());
        System.gc();
    }
    
    public static void main(String[] args) {
        // sayHello1(); // 多次执行该程序.打印结果都相同:1794106052
        sayHello2(); // 即便调用了System.gc(),但多次执行该程序.打印结果都相同:1794106052,垃圾回收是不是没用?
        
        System.out.println("总结:简单的说,JVM 垃圾回收机制适用于通过 new 创建的对象,深入理解可以查阅\"堆\"与\"栈\"!");
    }
}


 

 

 

通过上面的例子,我们了解到,System.gc()将内存中的对象,在Java程序中没有任何引用(指针指向)的数据销毁.那么如何取消引用呢?

常规情况下,对象的引用如下

Session s;                 // 空指针

s = new Session()   // s变为指向引用的指针

取消对new Session()的引用,可以直接将s再次变为空指针,也就是 s = null;这样JVM变清楚new Session()所分配的内存为垃圾数据,可以通过System.gc()销毁.

但通过情况下,对一个对象的引用是保存在数组或容器中,或其他对象中引用的.我们可以通过如下实例达到效果.

package cn.vicky.chapt14;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author Vicky.H
 */
public class FinalizeTest1 {

    public static void test1() {
        Player[] players = new Player[10];
        Arrays.fill(players, new Player());

        System.out.println("-------");
        System.out.println(players.hashCode());
        System.out.println(Arrays.hashCode(players));

        System.out.println("-------");
        for (Player player : players) {
            System.out.println(player.hashCode());
        }

        System.out.println("-------");
        for (int i = 0; i < players.length; i++) {
            players[i] = new Player();
        }
        System.gc(); // 回收第一次创建,但没有引用的Player对象.
        for (Player player : players) {
            System.out.println(player.hashCode());
        }

        System.out.println("-------");
        System.gc(); // 尝试回收players中的所有对象.[不会被回收]
        System.out.println("不会被回收");

        System.out.println("-------");
        Arrays.fill(players, null);
        System.gc(); // 尝试回收players中的所有对象.[回收成功]
    }

    public static void test2() throws InterruptedException {
        List<Player> players = new ArrayList<Player>();
        System.out.println(players.hashCode()); // 1
        for (int i = 0; i < 10; i++) {
            players.add(new Player());
        }
        System.out.println(players.hashCode());
        System.out.println("-------");
        for (Player player : players) {
            System.out.println(player.hashCode());
        }
        System.out.println("-------");
        System.gc(); // 回收集合中的对象失败.
        Arrays.fill(players.toArray(), null);
        System.gc(); // 回收集合中的对象失败.因为Collection.toArray() 是通过"拷贝"方式实现的.

        
        System.out.println("-------");
        Thread.sleep(5000);
       
        System.out.println("清空部分数据");
        // 清空部分数据
        List<Player> subList = players.subList(2, 4); // 数据指向的地址与原来数据是相同的
        for (Player player : subList) {
            System.out.println(player.hashCode());
        }
        // players.removeAll(subList); // 不能通过这样的方式,抛出java.util.ConcurrentModificationException
        subList.clear(); // 通过这样的方式,能直接修改players.
        
        System.gc();
        
        Thread.sleep(5000);
        System.out.println("清空所有的数据");
        players.clear(); // 清空所有的数据
        System.gc();
    }

    public static void main(String[] args) throws InterruptedException {
        // FinalizeTest1.test1();
        FinalizeTest1.test2();
    }
}

class Player {

    int id;
    String name;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁对象");
        super.finalize();
    }
}


 

package cn.vicky.chapt14;

/**
 *
 * @author Vicky.H
 */
public class FinalizeTest3 {
    
    public static void main(String[] args) throws InterruptedException {
        /*
        A a = new A(new B());
        System.gc();
        System.out.println("还有引用,无法销毁!");
        
        System.out.println("--------");
        Thread.sleep(5000);
        a = null;
        System.gc();
        System.out.println("没有引用,可以销毁销毁,由于B的引用是基于A的,所以,当A没有引用自动关联到B也没有引用,那么B也将会被销毁!");
        
        System.out.println("--------");
        Thread.sleep(5000);
         */
        
        
        B b = new B();
        A a1 = new A(b);
        A a2 = new A(b);    // a1,a2同时引用b
        
        b = null; // 这里只是将b设置为空指针,但无法修改a1,a2中对已经创建的内存的指向.
        System.out.println(a1.b.hashCode());
        System.out.println(a2.b.hashCode());
        
        a1 = null;
        System.gc(); // 销毁a1.但不会销毁b对象,因为a2还保留b的引用
        Thread.sleep(5000);
        
        a2 = null;
        System.gc(); // 销毁a2.也会销毁b对象,因为a1,a2都被销毁,b在程序中没有任何引用.
    }
}



class A {
    int id;
    String name;
    B b;

    public A() {
    }

    public A(B b) {
        this.b = b;
    }
    
    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁一个A对象");
        super.finalize();
    }
}

class B {
    int id;
    String name;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("销毁一个B对象");
        super.finalize();
    }
    
}


 

你可能感兴趣的:(java,String,session,object,null,Class)