读书笔记-GC基础垃圾收集算法整理

GC基础垃圾收集算法整理

简单概括如下4种算法:

  1. 标记-清除算法
  2. 复制算法
  3. 标记-整理算法
  4. 分代收集算法

对象死亡判断

在运行算法之前,需要判断对象的死亡,有如下2种方式来进行判断:

  1. 引用计数器算法
  2. 可达性分析算法

引用计数器算法

定义:对象中添加一个引用计数器,当有一个地方引用它时,就+1,引用失效时,计数器值就-1。现在的java已经弃用此方法。早期还是比较适用,再如Redis 1.0也是采用此方式。存在一个著名的相互引用的问题,故后续不再火了

可达性分析算法

设置一个GC Roots对象作为七点,从这些节点开始向下搜索,走过的链路叫做引用链。当一个对象到GC Roots没有任何引用链相连时,则此对象是可回收的。是目前jvm常用判断对象是否死亡的方法。

垃圾收集算法

如下为各种算法介绍

标记-清除算法

Mark-Sweep 标记-清除算法,分为2个阶段
第一阶段,标记处所有需要回收的对象。
第二阶段,清除所有标记过的对象。

image

主要存在2点不足:

  • 效率问题,标记和清除两个过程效率都不高
  • 空间问题,如图可见,结束之后存在大量不连续的内存碎片,此时需要分配一个较大的对象时,会触发再一次的垃圾收集动作。

此算法并不是完全的不使用了,而是后面的垃圾收集器中对其进行改造再使用。垃圾收集器介绍,会在下一节介绍。

复制算法

copy 标记-复制算法,可将内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块用完了,把还存活的对象复制到另一块上面,再把已使用过的内存空间一次清理掉。每次对整个半区进行内存回收。

image

1:1的比例在实际使用中并不适用,在虚拟机中,一般采用8:1:1的比例来分配Eden和Survivor,符合大多数对象朝生夕死的特性。个人的理解是,8:1是用来适用朝生夕死的特性,而分成2块Survivor,是用来作为对象进入老年代的依据。也可叫做fromto

解决了如下问题
1、内存碎片问题,主要解决了这个
2、按顺序分配内存,高效。

同时也有一些缺点
1、当对象大量存活时,频繁复制,效率降低
2、内存空间减少了一半,需要有额外的空间进行分配担保(故其实在老年代中一般是不能采用此方法的)

标记-整理算法

Mark-Compact算法,分为如下2步
1、标记需要清除的对象
2、把所有存活的对象向一端移动,直接清理掉边界以外的对象

image

分代收集算法

划分为新生代和老年代,每个年代可以选择自己适合的收集算法。

标记过程

上数算法中,都会去标记可回收或不可回收对象,标记的过程也是对对象进行可达性分析的过程。这项工作必须在一个能确保一致性的快照中进行,因此会出现GC停顿,称之为"stop the world"。

在jvm中会借助,安全点和安全区来对线程进行停顿。安全点是指,当发生GC时,各个线程会主动去轮询这个标志,发现中断标志为真时就自己中断挂起。但是对于不执行的线程无法运行到安全点,比如线程处于sleep或者blocked状态,这时候线程无法响应JVM的中断请求,就需要安全区来解决。当线程进入安全区时,无须关注中断标志,但是当线程离开安全区时,需要检查系统是否已经完成了根节点枚举(或者整个GC过程)。

总结

介绍了几种简单的垃圾收集算法,从中发现,每个算法都有自己的优缺点,但是绕不开的是"stop the world"。后面来分析,针对GC的停顿,不同的垃圾收集器是怎么处理的。

你可能感兴趣的:(读书笔记-GC基础垃圾收集算法整理)