垃圾回收算法 | 青训营笔记

72 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第14天

今天学习了垃圾回收算法

  1. 标记 - 清除

  • 在标记阶段

    • 程序会检查每个对象是否为活动对象,如果是活动对象,则程序会在对象头部打上标记。
  • 在清除阶段

    • 进行对象回收并取消标志位,另外,还会判断回收后的分块与前一个空闲分块是否连续,若连续,会合并这两个分块
  • 回收对象

    • 把对象作为分块,连接到被称为 “空闲链表” 的单向链表,之后进行分配时只需要遍历这个空闲链表,就可以找到分块
  • 分配

    • 程序会搜索空闲链表寻找空间大于等于新对象大小 size 的块 block。如果它找到的块等于 size,会直接返回这个分块;如果找到的块大于 size,会将块分割成大小为 size 与 (block - size) 的两部分,返回大小为 size 的分块,并把大小为 (block - size) 的块返回给空闲链表。

不足:

  • 标记和清除过程效率都不高;

  • 会产生大量不连续的内存碎片,导致无法给大对象分配内存。

2. 标记 - 整理

让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

优点:

  • 不会产生内存碎片

不足:

  • 需要移动大量对象,处理效率比较低。

3. 复制

将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理

  • 不足:
    • 只使用了内存的一半
  • 应用:
    • 现在的商业虚拟机都采用这种收集算法回收新生代,但是并不是划分为大小相等的两块,而是一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor。在回收时,将 Eden 和 Survivor 中还存活着的对象全部复制到另一块 Survivor 上,最后清理 Eden 和使用过的那一块 Survivor。
    • HotSpot 虚拟机的 Eden 和 Survivor 大小比例默认为 8:1,保证了内存的利用率达到 90%
    • 如果每次回收有多于 10% 的对象存活,那么一块 Survivor 就不够用了,此时需要依赖于老年代进行空间分配担保,也就是借用老年代的空间存储放不下的对象。