JVM:垃圾回收算法

垃圾回收算法

  • 一、分代收集理论
  • 二、标记-清除算法
  • 三、标记-复制算法
    • Appel式回收
  • 四、标记-整理算法

一、分代收集理论

当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”的理论进行设计,分代收集名为理论,实际上是一套符合大多数程序运行实际情况的经验法则,它建立在两个分代假说之上

  1. 弱分代假说:绝大多数对象都是朝生夕死的
  2. 强分代假说:熬过越多次垃圾收集过程的对象就越难消亡
  3. 跨代引用假说:跨代引用相对于同代引用仅占极少数

假说1,2共同奠定了多款常用的垃圾回收器的一致的设计原则:收集器应该将Java堆划分为不同的区域,然后将回收对象依据其年龄(即熬过垃圾回收过程的次数)分配到不同区域中存储。显而易见,如果一个区域中的对象大多数都是朝生夕死,难以熬过垃圾收集过程的话,那么把它们集中放在一起,每次回收只关注如何保留少量存活而不是去标记那些大量将要被回收的对象,就能以较低的代价回收大量的空间,如果剩下的都是难以消亡的对象,那么把它们集中放在一起,虚拟机就能以较低的频率来回收这个区域,这就同时兼顾了垃圾收集的时间开销和内存的空间有效利用

虚拟机一般会把Java堆划分为新生代和老年代两个区域,新生代中,每次垃圾收集时都会有大量对象死去,每次回收后存活的少量对象,将会逐步晋升到老年代中存放

根据垃圾收集的目标可分为:

  • 新生代收集(Minor GC/Young GC):目标只是新生代的收集
  • 老年代收集(Major GC/Old GC):目标只是老年代的收集。目前只有CMS收集器会有单独收集老年代的行为
  • 混合收集(Mixed GC):只目标是收集整个新生代和部分老年代的垃圾收集,目前只有G1收集器会有这种行为
  • 整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集

二、标记-清除算法

算法分为标记和清除两个部分,首先标记出需要回收的对象,在标记完成后,统一回收掉所有被标记的对象

算法的缺点:

  1. 执行效率不稳定,如果Java堆中包含大量的对象,而且其中大部分对象是需要回收的,这时必须进行大量标记和清除操作,导致标记和清除两个过程的执行效率都随着对象的数量增长而降低
  2. 内存空间碎片化,标记,清除之后会产生大量不连续的内存碎片,空间碎片过多会导致程序运行过程中需要分配较大对象时无法找到足够大的连续内存而不得不提前触发垃圾收集动作

JVM:垃圾回收算法_第1张图片

三、标记-复制算法

简称复制算法,解决了标记-清除算法的缺点

思想是将可用的内存按容量分为两块,每次只用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次性清理掉

由于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑内存空间碎片化的问题,只要移动堆顶指针,按顺序分配即可。这样实现简单,运行高效

缺点是:将可用内存缩小为原来一半,空间浪费太多
JVM:垃圾回收算法_第2张图片

Appel式回收

把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配内存只使用Eden和其中一块Survivor,发生垃圾收集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor,然后直接清理掉Eden区和已用过的Survivor空间

虚拟机默认Eden和Survivor大小比例是8:1,每次新生代中可使用内存空间为整个新生代容量的90%

四、标记-整理算法

标记-整理是针对老年代的算法

标记步骤和前面算法一样,整理步骤是让所有存活的对象都向内存空间的一端移动,然后直接清理掉边界以外的内存

JVM:垃圾回收算法_第3张图片

你可能感兴趣的:(JVM,java)