java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已较少了CLR中内存的GC的内存回收方式,是基于代的内存回收策略,其实在java中,JVM的内存回收策略也是基于分代的思想。这样做的目的就是为了提供垃圾
回收的性能,避免对堆中的所有对象进行检查时的降低程序的响应的性能,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作。基于分代的思想是:垃圾收集会更多的对一小部分内存
对象引用进行检查,这一小部分对象的生命周期也更短,从而加快了垃圾收集的性能。下面我们将来较少java中的基于代的内存回收算法的基本策略:
一、jvm堆内存的分代划分
在基于分代的内存回收策略中,堆空间通常都被换分为3个代,年轻代,年老代(或者tenured代),永久代。在年轻代中又被划分了三个小的区域,分别为:Eden(伊甸)区,S0区(survivor 0),S1区(survivor 1),如下图所示:
其中,新的对象总被分配到年经代中,当年轻代空间被填满时,这时需要执行minor GC,回收不再被引用的对象,并同时提升幸存的对象其年龄,年经代中的幸存对象都有年龄标识字段,一旦其达到一定的阈值,则仍然幸存的对象将被提升到年老代。
年老代的空间用于存放长时间幸存的对象,即生命周期较长的对象,一旦年轻代空间的幸存对象达到一定的年龄阈值后,将被自动提升到年老代,当年老代空间被对象填满时,这时执行一次Major GC。相较于minor GC, Major GC的执行次数要比minor GC要少很多,同时,Major Gc 执行的时间较Minor Gc要长。因为其涉及到更多的对象扫描。这种分代的思想,也是基于在实践中,对于新分配的对象具有更短的生命周期,年老的对象具有更长的生命周期所作出的较佳的选择。
与此同时,Minor Gc 和 Major Gc 在执行垃圾收集时,采取的是stop the world event ,即终止正在运行的线程,等GC执行完毕在恢复所有的线程。
对于永久代的内存,主要是用来存放元数据的相关信息,类及其方法的信息。当一个类不再使用时将会被回收,当执行Full GC时,将会扫描永久代内存,对其进行垃圾回收。
二、基于分代的垃圾回收的处理过程
首先,初始时,新对象被分配到Eden区域,s0,s1为空。当Eden中的空间被填满时,执行一次Minor GC。垃圾收集器会将被引用的对象移动s0区,不再被引用的对象将被删除,与此同时,对于幸存的对象标识其年龄为1. GC后,Eden和S1区为空如下图所示。
下一次执行Minor GC后,与先前的执行步骤相同,唯一的区别时,这次的被引用的对象将会被移动到S1区,与此同时在s0区幸存的对象的年龄会增加1,变成2,如下图所示。
当再次,执行Minor GC后,与先前的步骤相同,幸存对象会被移到S0区,给幸存对象年龄加1.如下图所示
最后执行Minor GC 时,发现 S1中的幸存的对象年龄达到8(假设阈值 设为8),此时该对象将被提升到老年代内存中,如下图所示。
Z
当老年代堆空间被对象填满时,将会执行一次Major Gc,将会清除老年代不再被引用的对象,与此同时,对该空间执行压缩。如下图所示。
参考引用:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html