Java-JVM(三)-垃圾回收策略

近期在读周志明老师的《深入理解Java虚拟机》现将我重点看的几个章节的知识总结一下,一来是对自己近期学习的知识做个记录,二来帮助其他小伙伴们快速了解下Java的JVM。


目录

1 如何判断对象可以回收

1.1 引用计数法

1.2 根搜索算法

1.3 引用的四种类型

2 如何实现垃圾回收(垃圾收集算法)

2.1 标记-清除算法

2.2 复制算法

2.3 标记整理法

2.4 分代收集算法

3 垃圾回收的具体实现(垃圾收集器)


1 如何判断对象可以回收

1.1 引用计数法

    简单来说就是给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加一,当引用失效时,计数器就减一,任何时刻中计数器都为0的对象就是不再被使用的对象。但是这种算法有一个缺点就是很难解决相互引用的问题,所以jvm并没有通过这个算法去进行垃圾回收。

1.2 根搜索算法

  在主流的商用程序语言中(Java和C#),都是使用根搜索算法(GC Roots Tracing)来判定对象是否存活。基本思路就是一系列可以作为Gc Roots的对象作为起始点,向下搜索所有相关的引用,形成引用链,当一个对象不属于任何引用链时(包括相互引用),就会被判定为可以回收的对象。

可以作为GC Roots的对象有以下几种:

  • 虚拟机栈(栈帧中的本地变量表)中的引用对象。
  • 方法区中的类静态属性引用的对象。
  • 方法区中的常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)的引用的对象。Java-JVM(三)-垃圾回收策略_第1张图片

1.3 引用的四种类型

Java 2 之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference),软引用(Soft Reference),弱引用(Weak Reference),虚引用(Phantom Reference)四种,引用强度依次变弱,回收风险依次变大。

  • 强引用:在程序代码中普遍存在,类似“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器就不会回收被引用的对象。
  • 软引用:描述一些还有用,但并非必须的对象(像不像鸡肋)。对于软引用关联着的对象,在系统即将发生内存溢出之前,将会把这些对象列进回收范围之中并进行第二次回收。如果回收之后系统还没有足够的内存,才会抛出内存溢出异常。
  • 弱引用:比软引用更弱。当垃圾收集器工作时,无论内存是否足够,都会讲弱引用关联的对象回收。
  • 虚引用:又叫幽灵引用或者幻影引用,是最弱的引用关系,一个对象是否有虚引用的存在,完全不会影响其生存时间,也不能通过虚引用来 取得一个对象实例。

2 如何实现垃圾回收(垃圾收集算法)

2.1 标记-清除算法

最基础的收集算法是“标记-清除”算法,先标记出所有需要回收的对象,然后统一回收掉被标记的对象。

此算法的两个缺点:

  1. 标记和清除过程效率都不高;
  2. 标记清楚后会产生大量不连续的内存碎片,当程序在运行过程中需要分配较大对象的时候,会因为找不到足够的连续内存而提前触发一次垃圾回收动作。

 

Java-JVM(三)-垃圾回收策略_第2张图片

2.2 复制算法

复制算法可将内存分为大小相等的凉快,每次只使用其中的一块,当一块内存用完了,就将存活的对象复制到另一块上面,然后再把上一块空间直接清理掉。但是这种算法太浪费内存,因为新生代中的对象%98都是朝生夕死的,所以将内存按照8:1:1的比例分成了三份Eden,S1, S2,先使用其中的Eden,S1,用尽后将存活对象复制到另一个S2上,然后再等Eden和S2用尽后在复制到S1,如此往复。

但是这样就会出现一个问题,如果进行一次回收后Eden+S1中存活的对象大于S2的内存大小,就需要老年代的内存担保(详细见1.4)。

Java-JVM(三)-垃圾回收策略_第3张图片

2.3 标记整理法

根据老年代的特点,有人提出了“标记-整理”算法,步骤是,先标记需要清除的对象,再讲存活的对象都向一端移动,然后直接清理掉边界以外的内存。

Java-JVM(三)-垃圾回收策略_第4张图片

2.4 分代收集算法

当前商业虚拟机的垃圾回收器都采用“分代收集”算法,一般是把Java堆分成新生代和老年代,这样就可以根据各个年代的特点采取最恰当的算法。

3 垃圾回收的具体实现(垃圾收集器)

简单对比下各个垃圾收集器的情况,具体的介绍就不说了。

名称 年代 线程情况 使用算法 Stop The World
Serial 新生代 单线程 复制算法 全程
ParNew 新生代 多线程 复制算法 全程
Parallel Scavenge 新生代 多线程 复制算法 全程
Serial Old 老年代 单线程 标记-整理算法 全程
Parallel Old 老年代 多线程 标记-整理算法 全程
CMS 老年代 并发 标记-清除算法 某阶段
G1 新生代/老年代 并发 标记-整理算法 某阶段

你可能感兴趣的:(java,jvm,垃圾回收)