JAVA 垃圾回收机制原理

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

 

[java] view plain copy
  1. package cn.vicky.chapt14;  
  2.   
  3.   
  4. /** 
  5.  * 
  6.  * @author Vicky.H 
  7.  */  
  8. public class FinalizeTest {  
  9.       
  10.     public static void main(String[] args) throws InterruptedException {  
  11.         Session session = new Session();  
  12.           
  13.         Object[] arr1 = new Object[5];  
  14.         Object[] arr2 = new Object[10];  
  15.           
  16.         System.out.println(session.hashCode());  
  17.         arr1[3] = session;  
  18.         System.out.println(arr1[3].hashCode());  
  19.         arr2[7] = session;  
  20.         System.out.println(arr2[7].hashCode());  
  21.           
  22.         System.out.println("--------------");  
  23.       
  24.         session = null;  
  25.         System.out.println(arr1[3].hashCode());  
  26.         System.out.println(arr2[7].hashCode());  
  27.         System.gc();  
  28.         System.out.println("第一次销毁session");  
  29.           
  30.         System.out.println("--------------");  
  31.         arr1[3] = null;  
  32.         System.gc();  
  33.         System.out.println("第二次销毁session");  
  34.         System.out.println(arr2[7].hashCode());  
  35.         System.out.println("--------------");  
  36.         arr2[7] = null;  
  37.         System.gc();  
  38.         System.out.println("第三次销毁session.可见,当内存中的对象在Java程序没有任何一个指向的时候,"  
  39.                 + "通过垃圾回收机制才能正在销毁对象.请注意,该条打印语句虽然执行顺序在System.gc()之后"  
  40.                 + "被执行的,但在打印\"销毁对象\"之前已经被打印出来,表示System.gc()是异步的."  
  41.                 + "它的执行不并影响主程序的执行,它将交与JVM虚拟机执行!");  
  42.         Thread.sleep(30000);  
  43.         System.out.println("总结:Java无法像C或C++那样通过free() delete 销毁对象,但Java可以通过"  
  44.                 + "取消对\"对象\"的所有引用并且调用System.gc()的方式来进行销毁.");  
  45.         System.out.println("Test Over");  
  46.     }  
  47. }  
  48. class Session {  
  49.     int id;  
  50.     String name;  
  51.   
  52.     @Override  
  53.     protected void finalize() throws Throwable {  
  54.         System.out.println("销毁对象");  
  55.         super.finalize();  
  56.     }  
  57. }  


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

 

[java] view plain copy
  1. package cn.vicky.chapt14;  
  2.   
  3. /** 
  4.  * 
  5.  * @author Vicky.H 
  6.  */  
  7. public class FinalizeTest2 {  
  8.       
  9.     public static void sayHello1(){  
  10.         System.out.println("hello world".hashCode());  
  11.     }  
  12.   
  13.     public static void sayHello2(){  
  14.         System.out.println("hello world".hashCode());  
  15.         System.gc();  
  16.     }  
  17.       
  18.     public static void main(String[] args) {  
  19.         // sayHello1(); // 多次执行该程序.打印结果都相同:1794106052  
  20.         sayHello2(); // 即便调用了System.gc(),但多次执行该程序.打印结果都相同:1794106052,垃圾回收是不是没用?  
  21.           
  22.         System.out.println("总结:简单的说,JVM 垃圾回收机制适用于通过 new 创建的对象,深入理解可以查阅\"堆\"与\"栈\"!");  
  23.     }  
  24. }  


 

 

 

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

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

Session s;                 // 空指针

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

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

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

[java] view plain copy
  1. package cn.vicky.chapt14;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Arrays;  
  5. import java.util.Iterator;  
  6. import java.util.List;  
  7.   
  8. /** 
  9.  * 
  10.  * @author Vicky.H 
  11.  */  
  12. public class FinalizeTest1 {  
  13.   
  14.     public static void test1() {  
  15.         Player[] players = new Player[10];  
  16.         Arrays.fill(players, new Player());  
  17.   
  18.         System.out.println("-------");  
  19.         System.out.println(players.hashCode());  
  20.         System.out.println(Arrays.hashCode(players));  
  21.   
  22.         System.out.println("-------");  
  23.         for (Player player : players) {  
  24.             System.out.println(player.hashCode());  
  25.         }  
  26.   
  27.         System.out.println("-------");  
  28.         for (int i = 0; i < players.length; i++) {  
  29.             players[i] = new Player();  
  30.         }  
  31.         System.gc(); // 回收第一次创建,但没有引用的Player对象.  
  32.         for (Player player : players) {  
  33.             System.out.println(player.hashCode());  
  34.         }  
  35.   
  36.         System.out.println("-------");  
  37.         System.gc(); // 尝试回收players中的所有对象.[不会被回收]  
  38.         System.out.println("不会被回收");  
  39.   
  40.         System.out.println("-------");  
  41.         Arrays.fill(players, null);  
  42.         System.gc(); // 尝试回收players中的所有对象.[回收成功]  
  43.     }  
  44.   
  45.     public static void test2() throws InterruptedException {  
  46.         List<Player> players = new ArrayList<Player>();  
  47.         System.out.println(players.hashCode()); // 1  
  48.         for (int i = 0; i < 10; i++) {  
  49.             players.add(new Player());  
  50.         }  
  51.         System.out.println(players.hashCode());  
  52.         System.out.println("-------");  
  53.         for (Player player : players) {  
  54.             System.out.println(player.hashCode());  
  55.         }  
  56.         System.out.println("-------");  
  57.         System.gc(); // 回收集合中的对象失败.  
  58.         Arrays.fill(players.toArray(), null);  
  59.         System.gc(); // 回收集合中的对象失败.因为Collection.toArray() 是通过"拷贝"方式实现的.  
  60.   
  61.           
  62.         System.out.println("-------");  
  63.         Thread.sleep(5000);  
  64.          
  65.         System.out.println("清空部分数据");  
  66.         // 清空部分数据  
  67.         List<Player> subList = players.subList(24); // 数据指向的地址与原来数据是相同的  
  68.         for (Player player : subList) {  
  69.             System.out.println(player.hashCode());  
  70.         }  
  71.         // players.removeAll(subList); // 不能通过这样的方式,抛出java.util.ConcurrentModificationException  
  72.         subList.clear(); // 通过这样的方式,能直接修改players.  
  73.           
  74.         System.gc();  
  75.           
  76.         Thread.sleep(5000);  
  77.         System.out.println("清空所有的数据");  
  78.         players.clear(); // 清空所有的数据  
  79.         System.gc();  
  80.     }  
  81.   
  82.     public static void main(String[] args) throws InterruptedException {  
  83.         // FinalizeTest1.test1();  
  84.         FinalizeTest1.test2();  
  85.     }  
  86. }  
  87.   
  88. class Player {  
  89.   
  90.     int id;  
  91.     String name;  
  92.   
  93.     @Override  
  94.     protected void finalize() throws Throwable {  
  95.         System.out.println("销毁对象");  
  96.         super.finalize();  
  97.     }  
  98. }  


 

[java] view plain copy
  1. package cn.vicky.chapt14;  
  2.   
  3. /** 
  4.  * 
  5.  * @author Vicky.H 
  6.  */  
  7. public class FinalizeTest3 {  
  8.       
  9.     public static void main(String[] args) throws InterruptedException {  
  10.         /* 
  11.         A a = new A(new B()); 
  12.         System.gc(); 
  13.         System.out.println("还有引用,无法销毁!"); 
  14.          
  15.         System.out.println("--------"); 
  16.         Thread.sleep(5000); 
  17.         a = null; 
  18.         System.gc(); 
  19.         System.out.println("没有引用,可以销毁销毁,由于B的引用是基于A的,所以,当A没有引用自动关联到B也没有引用,那么B也将会被销毁!"); 
  20.          
  21.         System.out.println("--------"); 
  22.         Thread.sleep(5000); 
  23.          */  
  24.           
  25.           
  26.         B b = new B();  
  27.         A a1 = new A(b);  
  28.         A a2 = new A(b);    // a1,a2同时引用b  
  29.           
  30.         b = null// 这里只是将b设置为空指针,但无法修改a1,a2中对已经创建的内存的指向.  
  31.         System.out.println(a1.b.hashCode());  
  32.         System.out.println(a2.b.hashCode());  
  33.           
  34.         a1 = null;  
  35.         System.gc(); // 销毁a1.但不会销毁b对象,因为a2还保留b的引用  
  36.         Thread.sleep(5000);  
  37.           
  38.         a2 = null;  
  39.         System.gc(); // 销毁a2.也会销毁b对象,因为a1,a2都被销毁,b在程序中没有任何引用.  
  40.     }  
  41. }  
  42.   
  43.   
  44.   
  45. class A {  
  46.     int id;  
  47.     String name;  
  48.     B b;  
  49.   
  50.     public A() {  
  51.     }  
  52.   
  53.     public A(B b) {  
  54.         this.b = b;  
  55.     }  
  56.       
  57.     @Override  
  58.     protected void finalize() throws Throwable {  
  59.         System.out.println("销毁一个A对象");  
  60.         super.finalize();  
  61.     }  
  62. }  
  63.   
  64. class B {  
  65.     int id;  
  66.     String name;  
  67.   
  68.     @Override  
  69.     protected void finalize() throws Throwable {  
  70.         System.out.println("销毁一个B对象");  
  71.         super.finalize();  
  72.     }  
  73.       
  74. }  

java中finalize()方法的使用

类的Finalize方法,可以告诉垃圾回收器应该执行的操作,该方法从Object类继承而来。在从堆中永久删除对象之前,垃圾回收器调用该对象的Finalize方法。注意,无法确切地保证垃圾回收器何时调用该方法,也无法保证调用不同对象的方法的顺序。即使一个对象包含另一个对象的引用,或者在释放一个对象很久以前就释放了另一个对象,也可能会以任意的顺序调用这两个对象的Finalize方法。如果必须保证采用特定的顺序,则必须提供自己的特有清理方法。


public class ObjectGc {
public ObjectGc() {}

public static void main(String [] args) {
ObjectGc og = new ObjectGc();
//很明显,og没有存在的意义了
og = null;
//由于垃圾回收是不定时的,我们还是手动回收看看吧
System.gc();
}
//当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
protected void finalize() {
System.out.println("我已经被垃圾回收器回收了...");
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值