博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
增量垃圾回收算法原理
阅读量:4294 次
发布时间:2019-05-27

本文共 1801 字,大约阅读时间需要 6 分钟。

为啥写这篇文章

最近面试的时候面试官会问些GC(Garbage Collection)的问题,除了标记清除比较好说之外,感觉其他的都比较难说清除,真是急煞我也。

想了好久,觉得之所以标记清除之所以比较好理解是因为讲述者的比喻非常形象:“给每个客人发一张卫生纸(别想多了),然后记录下客人的名单,要回收的时候就去问客人需不需要,把需要的标记成1,不需要的标记为0,然后逐个回收不需要的卫生纸”,多清晰!至于客人需不需要,那就是怎么遍历的问题啦,而标记是为了解决陷入询问死循环的问题(比如一个客人B说A需要我就需要,而A也说B需要我就需要,所以有必要标记一下这个人有没有问过,问过了就不问了!)。

那么增量GC又是什么东西呢?它有啥特殊的本领?

首先增量GC是一种GC(废话),它的存在是为了解决标记清除的长停顿问题(就是由于垃圾太多,虚拟机大哥清理了好久都没干完,不能腾出空来干正事)。

它有一个原则:

  • 垃圾永远是垃圾,不管GC跑了几遍都是垃圾

还有一个策略:

新生的对象不是垃圾

当虚拟机访问一个对象的时候,该对象及其相关的对象不是垃圾。

那具体是怎么操作的呢?

增量GC名称的由来跟全量GC相对,就是每次只处理一小部分的对象。具体还是分为标记阶段和清除阶段来阐述。

1.标记阶段

在这个阶段,垃圾回收器识别对象并且打标。

虚拟机关于对象的操作有以下几种:

  • 生成新的对象
  • 访问对象,包括读对象和写对象

对于发生这两种操作的对象,垃圾回收器会给他们打一个标,表示:该对象是有用的,不能回收!

同时会有一些事件来触发垃圾回收器的标记行为,比如说生成新对象、改变对象结构,或者是发生函数调用等等,这样垃圾回收器会被唤醒开始干活!打标!

等等,该怎么打标而不会重复而且确保所有对象都访问到呢?垃圾回收器每次醒来的时候程序中的对象都变了呀!不错,所以垃圾回收器要维持一个专门的结构来记录清理的状态,比较直观的想法就是有两个列表,分别是S和U,S用来记录所有的对象,U用来记录待标记的对象。具体的过程如下:

  • 首先待标记的是所有对象的根节点root;
  • 生成一个新的对象直接标记为1,把它记录到S中
  • 从U中取出一个对象,标记为1,然后把它能引用的并且标记为0的对象放入U。
  • 访问一个对象的时候,把它标记为1,然后把它的子对象标记为0的放入U。
  • 当U的长度为0的时候说明一轮GC完成!

等等!机智的你可能发现了,所有的对象都被标记为有用了!!!这样怎么能找出垃圾呢!!!

没错,这就是下一小节的内容了,千万别离开。

2.清理过程

上面给出了一个看似有理、实则好像没谱的过程,不,容我解释!没错,第一次标记过程确实是把所有对象都标记为有用了!但是第一次完成之后可是得继续的哦,我们完成一轮GC之后会把所有对象标记为0,这样好像所有的对象又回到原点了!是的,但是后面有惊喜哦!

我们再按照上面的过程走一遍,先标记root为1,把root的子对象放入U,。。。,漫长的时间过去了,垃圾回收器终于清空了U完成了第二次工作。这时候它发现,有一些对象的标记还是0!!!为什么呢?因为它们不能被访问到啊!!!(垃圾永远是垃圾)所以垃圾回收器终于相信了自己,开始愉快的工作了!

不清楚?见图!

【标记说明】绿色表示可用,黄色表示待标记,灰色表示不可达。C在第一轮中成为了垃圾
大家可以结合一小段代码来看
var a = A; // 拦截写操作,标记 Avar b = C; // 标记Cb = B;     // 标记B,这是C成为了漂浮垃圾,也就是不被任何对象引用gc();      // 这里会释放C// 这里总共引用了三个对象A,B,C// 可以看出执行gc的时候C已经成为了垃圾对象
简化起见,我们假设一次GC进行两轮回收,(正常情况下会进行增量标记,一轮GC过程会被分成很多次执行)
a:标记A,B,C
b:标记root及其可访问的对象 (这时候A,B,C对象都已经被标记了,root下面没有其他对象)
c:标记A、B、C,U长度为0,第一轮GC完成!
d:标记所有对象为0,第二轮GC开始
e:标记Root,这时root可达的只有A、B,所以将A、B放入U,C不变
f:标记A、B,U长度为0,C标记为0,可被垃圾回收器发现并回收!
参考资料
- 编译原理(龙书)第二版,垃圾回收一章
- tinypy的垃圾回收器实现代码

你可能感兴趣的文章
Laravel框架学习笔记之任务调度(定时任务)
查看>>
laravel 定时任务秒级执行
查看>>
浅析 Laravel 官方文档推荐的 Nginx 配置
查看>>
Swagger在Laravel项目中的使用
查看>>
Laravel 的生命周期
查看>>
CentOS Docker 安装
查看>>
Nginx
查看>>
Navicat远程连接云主机数据库
查看>>
Nginx配置文件nginx.conf中文详解(总结)
查看>>
Mysql出现Table 'performance_schema.session_status' doesn't exist
查看>>
MySQL innert join、left join、right join等理解
查看>>
vivado模块封装ip/edf
查看>>
sdc时序约束
查看>>
Xilinx Jtag Access/svf文件/BSCANE2
查看>>
NoC片上网络
查看>>
开源SoC整理
查看>>
【2020-3-21】Mac安装Homebrew慢,解决办法
查看>>
influxdb 命令行输出时间为 yyyy-MM-dd HH:mm:ss(年月日时分秒)的方法
查看>>
已知子网掩码,确定ip地址范围
查看>>
判断时间或者数字是否连续
查看>>