本文总结自:http://blog.csdn.net/zsuguangh/article/details/6429592
不像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代码。