Java GC(一)垃圾回收算法介绍

Java 怎么判断对象是否可以被回收?

有些语言采用引用计数来统计的,但是这种做法可能会遇见循环引用的问题(例如:A引用B,B引用A)。为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。 要注意的是,不可达对象不等价于可回收对象。

作为 GC Roots 中的对象有:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  • 方法区中的类静态属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈中JNI(即一般说的Native方法)中引用的对象
  • class,系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象

什么是 STW?

STW 是 GC 中很重要的概念,全称 Stop-the-world,即程序全局暂停时间,GC优化算法都是围绕减少STW的时间或频率。

常见垃圾回收算法

标记-清除

最基础的垃圾回收算法,分为两个阶段,先标记存活的对象,第二阶段清除未标记的对象
标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。
需要暂停整个应用,产生内存碎片,可能发生大对象不能找到连续的可用空间,导致 FullGC。
常用于老年代

复制

为了解决“标记-清除”算法内存碎片化的缺陷而被提出的算法。将内存划分为两部分,每次只使用其中一部分,当内存满后将存活的对象复制到另一块内存区域,并清除当前区域,完成回收。
需要两倍的存储空间不会出现碎片。当存活对象增多,效率会大大降低。
常用于新生代

标记-整理

结合了以上两个算法,标记阶段和“标记-清除”算法相同,区别是:标记后不清理对象,而是将存活对象移向内存的一端,使内存紧凑排列,然后清除其他区域的对象。
相比“标记-清除”算法会牺牲一些效率,但是不会出现碎片,提高内存利用率。
常用于老年代

增量回收

每次垃圾回收一部分区域,减少 STW 时间
但是线程切换上下文转换会造成垃圾回收时间增加

分代收集算法

分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将 GC 堆划分为老年代(Tenured/Old Generation)和新生代(Young Generation)。老年代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时会有大量垃圾需要被回收,因此不同区域可选择不同的算法。


Tags:,

Add a Comment

电子邮件地址不会被公开。 必填项已用*标注

15 − 10 =