学习Java垃圾回收机制

本文总结自:http://blog.csdn.net/zsuguangh/article/details/6429592


Java垃圾回收的意义与缺点

        不像C/C++语言一样,Java为创建对象申请的内存不需要编程人员进行显式的删除,而是由JVM进行内存监测并自动为无用的对象释放内存。

意义:

1.自动释放内存空间,减轻编程负担;

2.提高编程效率;

3.保护程序的完整性,避免内存指针问题。

缺点:

1.垃圾回收由JVM运行,会占据CPU时间,影响程序性能;

2.受限于回收算法性能和程序。


垃圾回收算法

        Java规范没有明确说明使用哪种回收算法,但是一般回收算法都需要做两件基本的事:(1)发现无用的对象;(2)回收无用对象的内存空间。

算法:

1.引用计数法(Reference Counting Collector):堆中每一个对象对应一个计算器,对象每被赋给一个变量时,计算器+1;对变量不再指向对象或除了scope时计数器-1,当计数器为0时,该对象被回收。这种方法运行效率很快,不会长时间中断程序的运行,但计数器增加了程序执行开销,包括CPU时间和内存。

2.Tracing算法(Tracing Collector):算法从根集(root set)开始扫描,识别出可达/不可达对象,并用某种方式标记可达对象,例如对每个可达对象设置一个或多个位。不可达对象将被回收。

3.Compacting算法(Compacting Collector):为了解决内存碎片问题的算法。由于程序不断地申请内存,垃圾回收器不断地回收内存,所以在堆内存中容易出现很多的碎片,对象内存之间出现一段空闲的内存。该算法在回收完成之后,会进行内存整理,将所有对象移到堆的一端,另一端则成了空闲区。而程序中的引用也将被更新,指向原本的对象的新的内存空间。在基于compacting回收器算法的实现中,一般增加句柄和句柄表。句柄与普通指针的区别在于,指针包含的是引用对象的内存地址,而句柄是由系统所管理的引用标识,该标识可以被重新定位到一个内存地址上。

4.Copying算法(Copying Collector):该算法的提出是为了克服句柄的开销和解决碎片整理的问题。算法开始把堆分成一个对象区和多个空闲区,程序从对象区为对象分配内存空间。当对象区空间满了,基于copying算法的回收器从根集扫描活动对象,并将每个活动对象复制到空闲区,也即在新的区里活动对象间没有内存碎片。这样新的区变成了对象区,原本的对象区变成了空闲区,程序将在新的对象区里分配内存空间。

5.Generation算法(Generation Collector):基于copying算法的回收器的缺点在于必须复制所有的对象到空闲区,这增占用了大量的CPU时间,增加了程序等待时间。程序设计里的一个规律:多数对象的存活时间较短,少数对象的存活时间较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代(generation)。由于多数对象存活时间较短,回收器将从最年轻的子堆开始回收对象。每一次回收后,存活下来的对象移到下一最高代的子堆中。回收根据generation层按不同频率回收对象,从而减少存活时间较长的对象的复制次数,节省了时间。

6.Adaptive算法(Adaptive Collector):从名字可以联想到,这是一种根据系统、程序特定情况选择不同的回收器,吸收每一种的优点,也避免了某一个算法在特定情况下存在的缺点。


系统调用

System.gc():在程序里运行该方法后,程序会向JVM请求进行一个垃圾回收,但仅仅是请求,也就是说回收器收到请求后,依然会判断即时系统是否需要进行垃圾回收。具体的实现方式需要参考当前jdk的版本信息。

/*
 *System.gc()使用方法
 */
class TestGC
{
    public static void main(String[] args)
    {
      new TestGC();
      System.gc();    //请求垃圾回收
      System.runFinalization();
   }
}
finalize():在对象被回收前,JVM一般会调用对象里的finalize()方法,作为对象被回收前的预处理。这有点像C++里的析构函数,在对象被释放时(delete/出了scope )调用析构函数。但又不是析构函数,因为C++里的释放对象是在析构函数里完成的,而Java由于垃圾回收的存在,真正完成释放的工作是垃圾回收主动完成的。而finalize()作为一种补充,在对象回收前给予编程者一定操作性,程序可以做一些回收前的工作,或者回收一些非Jav一般途径(new )申请的内存。使用该方法时需要在类里面重写该方法。

    class TestFina  
    {  
        public static void main(String[] args)  
        {  
          new TestFina();  
       }  

        @Override
        public void finalize(){
            System.out.println("finalize test");  
        }
    }  
上述程序创建了一个对象,但由于没有引用,该对象很快会被回收。回收前将调用finalize()方法,输出提示信息。


减少垃圾回收的开销

由上文知道,垃圾回收会占用系统开销,所以在编程当中应中注意这些问题,以便减少系统进行回收的开销,提高程序的性能。

1.不要显式调用System.gc()方法;

2.尽量减少临时对象的使用;

3.对象无用时显式置为null;

4.尽量使用StringBuffer而不是String,还有其他相似属性的类;

5.尽量使用基本类型int,long,而不是对应的对象Integer,Long;

6.尽量避免使用静态对象变量;

7.分散对象的创建或删除的时间。


关于垃圾回收的总结

1.垃圾回收存在不可预知性;

2.垃圾收集需要精确性;

3.存在不同类型的垃圾回收器;

4.垃圾回收的实现与JVM密切相关;

5.非Java核心开发人员可能无需深入到垃圾回收的实现当中,但懂得一些原理将有助于写出更优质的Java代码。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值