JVM的GC算法

18 阅读3分钟

JVM的GC算法主要分为两种:基于引用计数的垃圾回收算法和基于可达性分析的垃圾回收算法。

引用计数算法:在对象中添加一个引用计数器,每当有一个地方引用它时,计数器加1;每当有一个引用失效时,计数器减1。当计数器为0时,表示该对象已不再被使用,可以将其回收。

可达性分析算法:通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为"引用链",当一个对象到GC Roots没有任何引用链相连时,则证明此对象不可用。在Java语言中,可作为GC Roots的对象包括虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(即一般说的Native方法)引用的对象等。

可达性分析算法是目前主流的垃圾回收算法,因为它能够解决引用计数算法无法解决的循环引用的问题。同时,可达性分析算法也有多种实现方式,如标记-清除算法、复制算法、标记-整理算法等。

GC(Garbage Collection)使用的算法主要有以下几种:

标记-清除算法(Mark-and-Sweep):标记出所有活着的对象,然后清除所有未被标记的对象。标记-清除算法容易产生内存碎片,导致内存分配效率降低。
复制算法(Copying):将内存分为两个区域,每次只使用其中一个区域,当这个区域满了之后,将其中的存活对象复制到另一个区域,再将当前使用的区域清空,这样可以避免内存碎片问题。但是这种算法的缺点是需要占用较大的内存空间。
标记-整理算法(Mark-and-Compact):标记出所有存活的对象,然后将它们向一端移动,然后清除边界之外的所有对象。标记-整理算法可以避免内存碎片,但是需要移动存活对象,因此效率较低。
分代收集算法(Generational Collection):将内存分为多个代,一般是新生代和老年代两个代。新生代使用复制算法,因为新生代的对象大部分都是“朝生夕死”的,存活时间较短。老年代使用标记-整理算法,因为老年代的对象存活时间较长,不需要复制。
收集器的过程通常包括以下几个阶段:

标记阶段(Mark):标记出所有活着的对象,一般使用深度优先搜索算法。
清除阶段(Sweep):清除所有未被标记的对象。
压缩阶段(Compact):将所有存活对象向一端移动,然后清除边界之外的所有对象。这一阶段只在标记-整理算法和分代收集算法中出现。
不同的GC算法和收集器的选择取决于应用程序的需求和系统的资源情况。