Technology 10/13/2021
13
0
0

JVM - 垃圾回收算法

jvm , 算法 , 垃圾回收 , GC
JVM - 垃圾回收算法

JVM 垃圾判断算法:

  1. 引用计数算法(Reference Counting):给对象添加一个引用计数器,当有一个地方引用它,计数器加1,当一个引用失效,计数器减1,任何时候计数器值为0的对象就是不可能再被使用的。但是引用计数算法无法解决对象循环引用的问题(对象A应用对象B,对象B引用对象A,当A对象和B对象外部都不再存在引用时,它们之间仍然存在一个引用,这时引用计数算法就无法对其进行回收)。
  2. 跟搜索算法(GC Root Tracing):在实际的开发语言中(java、C##等)都使用的是根搜索算法判断对象是否存活,这种算法的基本思路是通过一系列的被称为 GC Roots 的点作为起始进行向下搜索,当一个 GC Roots 没有任何引用链(Referencd Chain)相连,则表示此对象是不可用的。

在java语言中,GC Roots包括:

  • 在jvm栈(帧中的本地变量)中的引用;
  • 方法区中的静态引用;
  • JNI(一般为Native方法)中的引用;

GC算法:

  1. 标记-清除算法(Mark-Sweep):
    算法分为标记、清除两个阶段:首先标记出所有需要回收的对象,然后清除所有被标记的对象;
    特点:

    • 效率问题:标记和清除两个阶段效率都不高;
    • 空间问题:标记清理之后会产生大量不连续的内存碎片,空间碎片太多可能会导致后续使用中无法找到足够的连续内存而提前出发另一次垃圾收集动作;
  2. 标记-整理算法(Mark-Compact):
    算法分为标记、整理两个过程,和标记-清除不一样的是,标记-整理算法将标记存活的对象移动到同一端,然后将这端边界另一侧的内存直接清理;
    特点:

    • 没有碎片;
    • 比标记-清除算法耗费更多的时间进行整理;
  3. 复制算法(Copying):
    将可用内存分为两块,每次只使用其中的一块,当半区内存用完了仅仅把还存活的对象复制到另一块内存中,然后把原来的整块内存全部清理掉。
    特点:

    • 不会存在碎片问题:因为回收是清楚整个半区内存,内存分配时不用考虑碎片问题,只需要移动栈顶指针,按顺序分配内存就可以了;
    • 内存缩小一半,成本太高,有一半内存使用不可用;
    • 只需要扫描存活的对象,效率较高,但是对象存活率高的时候,效率有所下降;
    • 非常适合生命周期比较短的对象,因为每次回收总能回收大部分的对象,复制的开销比较小;
      现代的商业虚拟机使用这种算法回收新生代:
      将内存分为一块较大的Eden空间和两块较小的Surivivor空间(From Survivor 和 To Survivor),每次使用Eden和一块Surivivor空间,在回收时,将Eden和Surivivor空间中存活的对象复制到另一块Surivivor空间,然后清理Eden和使用过的Surivivor空间。HotSpot默认的Eden空间和两块Surivivor空间比例为8:1:1;
  4. 分代算法(Generational):
    现代商业虚拟机都是采用分代算法进行垃圾回收,根据对象不同的存活周期将内存(堆内存)分为几块区域,Java一般将堆内存分为新生代和老年代两块区域,这样就可以根据各个代的不同特点采用最适合的垃圾回收算法。例如:新生代每次GC都有大批的对象死去,只有少数的对象存活,那就可以采用复制算法(Copying),只需付出少量对象的存活成本就可以完成收集。

新生代:

新生代分为三个区:Eden区和两个Surivivor区(From Survivor 和 To Survivor,两者是完全对称的,轮流替换,可以通过参数设置Survivor个数)
对象在Eden区中生成,当Eden区满了的时候,存活的对象将被复制到一个Surivivor区(From Survivor),当这个Surivivor区(From Survivor)也满了的时候,将其中仍然存活的对象复制到另外一个Surivivor区(To Survivor),当第二个Survivor(To Survivor)区也满了的时候,将依然存活的对象复制到老年代。

老年代:

存放经过一次或者多次GC仍然存活的对象,一般采用标记-清除算法(Mark-Sweep)或标记-整理算法(Mark-Compact)进行GC,有多种垃圾回收器可以选择,每一种垃圾回收器可看作一个GC的具体实现。

永久代:jdk7以后就不存在了(参考:JVM-运行时数据区

并不属于堆,但是垃圾回收器会涉及到这个区,存放每一个Class的结构信息,包括常量池、字段描述、方法描述等,与垃圾回收的java对象关系不大。

Comments