java垃圾回收--转载http://qiang106.iteye.com/blog/571182

内存管理往往是很多应用程序的关键部分,像在C/C++这些需要手动管理内存的语言中编程,稍有缺陷就有可能导致大量内存泄漏,从而使程序崩溃。Java提供了一个自动回收内存的垃圾收集器,让Java程序员能从内存管理中解脱出来,但是也存在缺点,那就是不能完全控制它什么时候执行什么时候不执行。 

      垃圾回收器,通常就叫它GC,GC实际上是一个受JVM控制的程序,它的核心任务就是删除Java程序运行不再触及的任何对象。所谓的“触及”是指Java程序中任何一个活动的线程存在对这个对象的引用。 


      GC是什么时候运行呢?  
     GC受JVM的控制,JVM决定什么时候运行GC,我们平常可以在程序中请求JVM进行垃圾回收,从而释放更多的内存供程序使用,但是在任何情况下,请求都无法保证JVM会答应我们的请求,当我们请求回收时,短期内JVM会进行垃圾回收,但这没有任何保障。JVM会在它觉得必要的时候进行回收,如下面第一段和第二段代码,虽然第二段代码执行次数更多,但GC觉得内存不够了,它进行了回收,到最后占用的内存反而比第一段的代码占用的内存少。第三段代码我们可以看得到我们请求GC时还我内存的效果。System.gc(),看源码可以知道,实际上它调用了Runtime 的gc()方法。 
Java代码    收藏代码
  1. public static void main(String[] args) {  
  2.         Runtime rt = Runtime.getRuntime();  
  3.         System.out.println("Total JVM memory:" + rt.totalMemory());  
  4.         System.out.println("Before Memory=" + rt.freeMemory());  
  5.         Date d = null;  
  6.         for(int i=0;i<100000;i++){  
  7.             d = new Date();  
  8.             d = null;  
  9.         }  
  10.         System.out.println("After Memory=" + rt.freeMemory());  
  11.         rt.gc();  
  12.         System.out.println("After GC Memory=" + rt.freeMemory() );  
  13.         System.out.println("=======================");  
  14.         System.out.println("Before Memory=" + rt.freeMemory());  
  15.         for(int i=0;i<10000000;i++){  
  16.             d = new Date();  
  17.             d = null;  
  18.         }  
  19.         System.out.println("After Memory=" + rt.freeMemory());  
  20.         rt.gc();  
  21.         System.out.println("After GC Memory=" + rt.freeMemory() );  
  22.           
  23.         System.out.println("=======================");  
  24.         System.out.println("Before Memory=" + rt.freeMemory());  
  25.         Date[] ds2 = new Date[1000000];  
  26.         for(int i=0;i<1000000;i++){  
  27.             ds2[i] = new Date();  
  28.         }  
  29.         System.out.println("After Memory=" + rt.freeMemory());  
  30.         rt.gc();  
  31.         System.out.println("After GC Memory=" + rt.freeMemory() );  
  32.     }  

执行结果: 
Java代码    收藏代码
  1. Total JVM memory:5177344  
  2. Before Memory=4945624  
  3. After Memory=4254216  
  4. After GC Memory=5024744  
  5. =======================  
  6. Before Memory=5024744  
  7. After Memory=4197480  
  8. After GC Memory=5020280  
  9. =======================  
  10. Before Memory=5020280  
  11. After Memory=18211424  
  12. After GC Memory=46200736  

请求GC的时候,JVM往往并不会马上响应我们的要求,finalize()方法是每一个对象回收时都会运行一次的方法,并且仅一次,一般不要重写finalize()方法,在此方法中可以让该需要回收的对象起死回生,让它重新被引用,从而让该对象免于被回收,但是此方法只执行一次,当下次该对象符合回收条件的时候,JVM会判断已经执行过finalize()了,将不再执行了。运行如下代码,你会发现请求并不那么有效,被回收的对象也不是那么有先后顺序了。 

Java代码    收藏代码
  1. public class FinalizeTest {  
  2.     int num;  
  3.       
  4.     public FinalizeTest(int num){  
  5.         this.num = num;  
  6.     }  
  7.     /** 
  8.      * @author ZhangXiang 
  9.      * @param args 
  10.      * 2010-1-15 
  11.      */  
  12.     public static void main(String[] args) {  
  13.         FinalizeTest ft = null;  
  14.         for(int i=0;i<100000;i++){  
  15.             ft = new FinalizeTest(i);  
  16.             ft = null;  
  17.             System.gc();  
  18.         }  
  19.     }  
  20.   
  21.     @Override  
  22.     protected void finalize() throws Throwable {  
  23.         super.finalize();  
  24.         System.out.println("FinalizeTest"+this.num);  
  25.     }  
  26.       
  27. }  


     GC是怎么样工作的呢?  
    首先我们得要了解垃圾回收的条件,前面也提到:当没有任何活的线程能够访问一个对象时,该对象就符合垃圾回收的条件了,有一个例外,String存在于String常量池中,虽然它也是对象,但我们感觉它更像常量一样,表现更反复无常。虽然我们没办法完全控制GC工作,但是我们还是能适当指引它运行,为其回收对我们没用的对象创造条件: 

1、空引用  

很简单,只需要把引用我们不需要的对象的变量设置为Null,如下面的代码 
Java代码    收藏代码
  1. Date date = new Date();  
  2. Sytem.out.println(date);  
  3. date = null;  

2、为变量重新赋值  

   就是给引用垃圾对象的变量重新赋一个值,如下面的代码第一次new得到的象在变量被赋予一个新对象的时候就已经符合回收的条件了,当然等待它的也就是回收的命运了 
Java代码    收藏代码
  1. Date date = new Date();  
  2. Sytem.out.println(date);  
  3. date = new Date();  

3、隔离引用  

     当对象中的属性对其它对象进行交叉引用,如果两个对象都存在彼此的引用,即使其它对这两个对象的引用都被删除,但是这两个对象都还存在一个有效引用,这样不会符合回收条件,要让GC能够回收它们就需要打破这样的一个环,如果是多个对象也许就是拆散一个网,隔离出来不再需要的对象,从而让它满足被回收的条件,如以下代码,当到doSth()时i3就已经满足被回收的条件了。 
Java代码    收藏代码
  1. public class Island {  
  2.     Island i;  
  3.     Island ii;  
  4.     /** 
  5.      * @author ZhangXiang 
  6.      * @param args 
  7.      * 2010-1-15 
  8.      */  
  9.     public static void main(String[] args) {  
  10.         Island i1 = new Island();  
  11.         Island i2 = new Island();  
  12.         Island i3 = new Island();  
  13.           
  14.         i1.i = i2;//i1引用i2  
  15.         i2.i = i3;//i2引用i3  
  16.         i3.i = i1;//i3引用i1  
  17.           
  18.         i1.ii = i3;//i1又引用i3  
  19.         i2.ii = i1;//i2又引用i1  
  20.         i3.ii = i2;//i3引用i2  
  21.           
  22.         //隔离出i3,使它满足被回收的条件  
  23.         i2.i= null;  
  24.         i1.ii = null;  
  25.         //doSth();  
  26.     }  
  27. }  

    java GC虽然是自动执行的,但是了解它的原理,知道它是怎么执行的,有时候在实际开发中对我们的帮助还是蛮大的,这也是平常找工作面试、笔试常考的知识点,学习了好多次,总是隔段时间就要忘记不少,记下来分享下,也起到提醒自己的作用吧,当是笔记咯。 
    一般都只是看看别人写的博,自己很少写,有时看看自己写的文章,发现差距还是很大,其实写博也是记录自己成长的一种方式吧,学习中,还请大家多多指教。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值