[Java虚拟机]垃圾回收GC算法

[Java虚拟机]垃圾回收GC算法

在jvm中,程序计数器、虚拟机栈、本地方法栈都是随线程而生随线程而灭,栈帧随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理,因此内存垃圾回收主要集中于java堆和方法区中,在程序运行期间,这部分内存的分配和使用都是动态的。

一、判断对象是否存活的JVM两种计数算法

1. 引用计数算法

引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。

缺点:引用计数算法无法解决对象相互循环引用的问题。

[Java虚拟机]垃圾回收GC算法

2. 可达性分析计数算法(根搜索算法)

实际开发语言比如java、C#等都是采用可达性分析计数算法判断对象是否存活

可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。

GC Roots主要包括:
1、对象的引用,位于虚拟机栈中。
2、方法区中的静态引用。
3、本地方法栈中JNI的引用。【JNI一般指的是Native方法】
简单地说,GC Root 就是经过精心挑选的一些引用

[Java虚拟机]垃圾回收GC算法

二、垃圾收集算法

1. 标记清除算法复制算法

其分为两个阶段:标记阶段和清除阶段。

  • 在标记阶段,标记所有由 GC Root 触发的可达对象。此时,所有未被标记的对象就是垃圾对象。
  • 在清除阶段,清除所有未被标记的对象。
  • 问题就是空间碎片问题。如果空间碎片过多,则会导致内存空间的不连续。
2. 复制算法(Copying)

核心思想是将原有的内存空间划分为大小相等的两块,每次只使用一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中。之后清除正在使用的内存块中的所有对象,之后交换两个内存块的角色,完成垃圾回收。

复制算法的缺点是要将内存空间折半,极大地浪费了一半内存空间。现在的商业虚拟机都使用这种复制算法来进行新生代的垃圾收集!因为在对象存活率高的时候,复制算法就显得效率低下

3. 标记-整理算法(Mark-Compact)

是标记清除算法的优化版,分为标记阶段、整理阶段。

  • 标记阶段和标记清除算法中的标记阶段是一样的。
  • 整理阶段,其则是将所有存活的对象整理在内存的一边,之后清理边界外的所有空间。
  • 标记-整理算法(Mark-Compact)不会产生内存碎片,但是会多花点时间用在整理(Compact)上面。
4. 分代收集算法(Generational Collection)

把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

  • 在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那新生代选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
  • 老年代中因为对象存活率高、没有额外空间对它进行分配担保,老年代就使用“标记-清理”或“标记-整理”算法来进行回收。
5. 四种回收算法总结

标记清除算法

分为标记阶段和清除两阶段。标记清除算法最大的问题就是空间碎片问题。比较适合在存活对象比较多的情况。

复制算法(Copying)

复制算法的缺点是浪费了一半内存空间。现在的商业虚拟机都使用这种复制算法来进行新生代的垃圾收集!因为在对象存活率高的时候,复制算法就显得效率低下比较适合存活对象比较少的情况。

标记整理算法(Mark-Compact)

标记整理算法是标记清除算法的优化版,标记-整理算法(Mark-Compact)不会产生内存碎片,但是会多花点时间用在整理(Compact)上面!

分代收集算法(Generational Collection)

新生代选用复制算法,老年代使用“标记-清理”或“标记-整理”算法来进行回收。

三、垃圾回收算法总结

[Java虚拟机]垃圾回收GC算法