《深入理解java虚拟机》笔记(5)垃圾回收算法及垃圾收集器
一、标记-清除算法
算法:分为标记和清除两个阶段,首先标记出所有需要回收的对象,再对标记对象进行回收。
不足之处:效率不高,会产生大量不连续内存碎片,导致下次分配较大内存时,若内存不足不得不触发垃圾回收操作。
此算法为最基础算法,其他算法都是在此算法基础上改进而得到的。
二、复制算法
算法:将可用内存按容量大小划分为两块,每次只使用其中一块,当这块用完之后,就将还存活的对象复制到另外一块上面,再把已使用过的那块清理掉。
缺点:这种算法的代价就是将内存缩小为了原来的一半。
此种算法常运用于回收新生代。
三、标记-整理算法
算法:和标记-清除算法前部分类似,只是不会清除回收,而是将存活对象移动到一端,再直接清理掉边界以外的内存。
此种算法常运用于老年代。
四、分代收集算法
此算法为目前大部分JVM采用的方法,其核心思想是根据对象存活不同的周期划分为不同的域,一般分为老年代(Old Generation)和新生代(Young Generation)。
老年代特点是每次只会回收小部分对象,而新生代每次都会有大量的对象需要回收。因此可以针对不同区域选择不同算法。
- 新生代
1、采用的是复制算法,因为每次会回收大量对象,因此需要复制的操作比较少。
2、新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。
3、当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收。
4、新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)。
- 老年代
1、采用的是标记-整理算法。
2、在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
3、内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率比较高。
- 永久代
1、用来存储class类,常量,方法描述等。对永生代的回收主要包括废弃常量和无用的类。
五、常用垃圾收集器
下面介绍HotSpot虚拟机提供的几种垃圾收集器(有连线的表明他们可以搭配使用):
1、Serial/Serial Old
最古老的收集器,是一个单线程收集器,用它进行垃圾回收时,必须暂停所有用户线程(Stop-The-World)。Serial是针对新生代的收集器,采用Copying算法;而Serial Old是针对老年代的收集器,采用Mark-Compact算法。优点是简单高效,缺点是需要暂停用户线程。
2、ParNew
Seral/Serial Old的多线程版本,使用多个线程进行垃圾收集。
3、Parallel Scavenge
新生代的并行收集器,回收期间不需要暂停其他线程,采用Copying算法。该收集器与前两个收集器不同,主要为了达到一个可控的吞吐量。
4、Parallel Old
Parallel Scavenge的老年代版本,采用Mark-Compact算法和多线程。
5、CMS
Current Mark Sweep收集器是一种以最小回收时间停顿为目标的并发回收器,因而采用Mark-Sweep算法。
6、G1
G1(Garbage First)收集器技术的前沿成果,是面向服务端的收集器,能充分利用CPU和多核环境。是一款并行与并发收集器,它能够建立可预测的停顿时间模型。