垃圾回收算法原理

首先在垃圾划分上:

垃圾收集算法可以划分为 “引用计数式垃圾收集”(Reference Counting GC) 和 “追踪式垃圾收集”(Tracing GC) 两大类,这两类也常被称作“直接垃圾收集”和“间接垃圾收集”。其中追踪式垃圾收集就是上文所说的可达性分析。

引用计数法有一定缺陷,因此虚拟机主流采用可达性分析

而又根据分代收集理论,绝大多数对象都是朝生夕灭的,同时存活时间越长的对象,越容易继续存活下去。

因此至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域。

同时跨代引用是不可避免的,尽管跨代引用是比较少的一部分。

如何处理跨代应用呢

把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。 此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描。

image.png
标记清除算法是分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程。

缺点:

第一个是执行效率不稳定,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;

第二个是内存空间的碎片化问题,标记、清除之后会产生大 量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找 到足够的连续内存而不得不提前触发另一次垃圾收集动作。

标记复制算法适用于新生区的划分
如果内存中多数对象都是存活的,这种算法将会产生大量的内存间复制的开销,但对于多数对象都是可回收的情况,算法需要复制的就是占少数的存活对象,而且每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况,只要移动堆顶指针,按顺序分配即可。这样实现简单,运行高效

其缺陷也显而易见,这种复制回收算法的代价是将可用内存缩小为了原来的一半,空间浪费未免太多了一点。

改进:新生代中的对象有98%熬不过第一轮收集。因此并不需要按照1∶1的比例来划分新生代的内存空间。但这就需要依赖其他内存区域(实际上大多就是老年代)进行分配担保(Handle Promotion)。

在对象存活率较高时就要进行较多的复制操作,效率将会降低。

标记整理算法

针对老年代对象的存亡特征,提出了另外一种有针对性的 “标记-整理”(Mark-Compact)算法,其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可 回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。

还有一种“和稀泥式”解决方案可以不在内存分配和访问上增加太大额外负担。
做法是让虚拟机平时多数时间都采用标记-清除算法,暂时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再采用标记-整理算法收集一次,以获得规整的内存空间。前面提到的基于标 记-清除算法的CMS收集器面临空间碎片过多时采用的就是这种处理办法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值