一 标记-删除算法(Mark-Sweep)算法
首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
缺点:1.效率不高;2.空间问题 产生大量的内存碎片
二 复制算法(Copying)
将可用内存分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块上面,然后把使用过的内存空间一次清理掉。
优点:实现简单,运行高效;缺点:内存空间变为原来的一半
五
现行的垃圾回收器用分代的方式来采用不同的回收设计。根据对象生存时间的长短,把堆内存分 成3个代。Young(年轻代),Old(老年代),Permanent(永久代)。
Young:主要是用来存放新生的对象。
Old:主要存放应用程序中生命周期长的内存对象。
Permanent:是指内存的永久保存区域,.它和存放Instance的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理。
其实在JVM中对于垃圾回收时不论采用哪种算法机制来设计垃圾回收器,都会利弊参半,因此实际上实现垃圾回收时总会综合使用多种设计方式也就是基于多种算法的一个综合应用。java现行JVM中基于不同代的特点之上采用不同的回收算法,从而充分利用种回收算法的优点。
首先提前了解下(Minor GC),(Major GC / Full GC)
GC(Minor GC):指发生在新生代的垃圾收集动作,它不会导致老年代里进行垃圾收集动作发生,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。
GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10 倍以上。
再看上图:划分了不同代后,由于GC主要是发生在对象经常消亡的新生代,如有IBM 的专门研究表明,新生代中的对象98%是朝生夕死的,复制算法实现简单,运行高效,对于复制量不是很大的情况下使用比较合理。所以现在商业虚拟机都采用复 制算法来回收新生代。再看新生代内划分为三个小块。因为新对象经过一次GC后存活下来的就会很少了,不需要按照1:1的比例来划分内存空间,而是设计成将 内存分为一块较大的Eden空间各两块较小的Survivor空间(这两个Survivor空间就是Survivor space:From Survivor或To Survivor。这两个Survivor空间是一样大小的。例如,新生代大小是10M(Xmn10M),那么缺省情况下 (-XX:SurvivorRatio=8),Eden Space 是8M,From和To都是1M。),每次使用Eden和其中的一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性地 拷贝到另一块Survivor空间上(如果此时Survivor空间不足怎么办,请看下面),最后清理掉Eden各刚才用过的Survivor的空间。
当 new一个对象时,先在Eden Space上分配,如果Eden Space没有足够的内存空间了,此时就要做一次Minor GC。Minor GC后,要把Eden和From中仍然活着的对象们复制到To空间中去。一般,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1。对象在 Survivor 区中每熬过一次 Minor GC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
说到这可以说明(如果此时Survivor空间不足怎么办) 这个问题了,不用担心在发生 Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,改为直接进行一次Full GC ,如果小于,说明老年代空间还有足够的空间,则要查看设置参数HandlePromotionFailure是否为true,如果是那只会完成这一次 Minor GC,GC后的新生代中活下来并符合老年代条件的对象就被promote到老年代空间,还有To Survivor空间不能容纳下Minor GC后活着的某个对象也会被promote到老年代空间,还有另一种情况就是如果新进来的一个大对象,Eden也没有足够空间存放的时也会直接把它 promote到老年代空间 ;如果false 则也要改为直接进行一次Fulll GC。对于参数HandlePromotionFailure它是指在Survivor轮换备份的过程中,Survivor无法容纳的对象是否直接进入老 年代。谈到怎么进入老年代,顺便说下另一种情况,并不是所有要进入老年代区域的对象年龄必须达到:MaxTenuringThreshold设定的值的, 如果Survivor空间中相同age(例如,age=5)对象的所占内存空间总和大于等于Survivor空间的一半,那么age>=5的对象在 下一次Minor GC后就可以直接promote到老年代,而不用等到age增长到阈值。
说到这里,再在已经能对GC到底在什么时候开始工作这个问题做个总结了:当在new 对象时,首先考虑在Eden Space上分配内存,如果Eden满了则 进行minor gc,晋升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;