Conservative GC (Part one)
保守式GC
保守式GC(Conservative GC)指“不能识别指针和非指针的GC”
不明确的根
不明确的根(ambiguous roots),下面三类都可以作为根。事实上是不明确的根
- 寄存器
- 调用栈
- 全局变量空间
以栈为例:在调用栈中有调用帧(call frame),调用帧里面装着函数内的局部变量和参数值。不过局变量中如果有c语言里面的int、double这样的数值,也就会有void*这样的指针。也就是说调用帧里既有数值(非指针),也有指针。

GC不能识别指针和非指针,这类叫做不明确根。这样的GC算法称为保守式GC。
指针和非指针的区别
在不明确根这一条件下,GC不能准确识别指针和非指针。任意一个空间里可能是根也可能不是根。这样一来,GC在处理时就会出现大量指针识别错误。因此保守式GC会检查不明确的根,以某种程度的精度来识别指针。
- 保守式GC使用下列几种方式检查根
- 是不是被正确对齐的值:32的cpu下指针的值为4的倍数,64位为8的倍数。如果是其他情况,就会被识别为非指针。
- 是不是指着堆内 :当分配了GC专用堆时,对象就会被分到堆里。也就是说指向对象的指针一定指向这个堆。
- 是不是指着对象的开头:调查不明确的根内的值是不是指着对象的开头。在标记清除那一节中,我们介绍了BiBOP.把对象按照固定大小对齐,核对对象的值是不是对象固定大小的倍数。
以上三种举措,根据内存布局和对象结构等检查项也会有所变化。
貌似指针的非指针
遇到非指针和堆内的对象的地址一样的情况。这个时候就无法识别这个值是非指针。这就是貌似指针的非指针(fasle pointer)。如图示:

保守式GC将这种“貌似指针的非指针”看出指针对象。我们把这种情况叫做“指针的错误识别”。
打个比方,在采用 GC 标记 - 清除算法的情况下,一找到貌似指针的非指针,程序就会将非指针指向的对象错误地识别为活动对象,对其进行标记。因为被错误识别的对象不会被废弃而会被保留,所以遵守了GC的原则—“不废弃活动对象”。像这样,在运行GC时采取的是一种保守的态度,即“把可疑的东西看作指针,稳妥处理”,所以我们称这种方法为“保 守式 GC”。
不明确数据结构
当基于不明确个根运行GC时,我们需要从对象的头部获取类型信息。比如说C中的结构体设置flag,通过flag就可以识别。
如果能从头中获得结构体信息,GC就能识别出对象域里的值是指针还是非指针。以C为例,所有的域里都包含类型信息,只要没有放入与类型不同含义的值,就有可能正确识别指针。
下列展示的结构体就会变成不明确的数据结构(ambiguous data structures)。
union{
long n;
void *ptr;
} ambiguous_data;
因为ambiguous_data是联合体,所以它可能包括指针ptr,或者非指针n。那么GC就无法准确识别出它是不是指针。当对象具有这样的数据结构时,GC不仅会错误识别不明确根,也会错误识别域里的值。
优点
- 语言处理程序不依赖于GC
易于编写语言处理程序,处理程序基本不用在意GC就可以编写代码。语言处理程序的实现者即使没有意实到GC的存在,程序也会自己回收垃圾。因此语言处理程序的实现要比准确式GC简单。
缺点
- 识别指针和非指针需要付出成本
识别不明确的根和数据结构的值为“指针”或“非指针”时,我们需要付出一定的成本。
- 错误识别指针会压迫堆
保守式 GC 会把被引用的对象错误识别为活动对象。如果这个对象存在大量的子对象,那么它们一律都会被看成活动对象。因为程序把已经死了的非 活动对象看成了活动对象,所以垃圾对象会严重压迫堆。
- 能够使用GC的算法有限
在无法正确识别指针的环境中,我们基本上不能使用GC复制算法等移动对象的GC算法。我们想用不明确的根这么办的话,就可能把非指针重写了。此外,在对象内重写指针时,也有可能因为不明确的数据结构而重写了非指针。一旦重写了非指针,就会产生 意想不到的 BUG。
准确式GC
准确式GC(Exact GC)和保守式GC正好相反,它是能正确识别指针和非指针的GC。
正确的根
准确式GC和保守式GC不同,它是基于能准确识别指针和非指针的“正确的根(exact roots)”来执行GC的。
创建根的方法有很多种,不过这些方法的共同点就是需要“语言处理程序的帮助”,所以正确的根的创建方法是依赖于语言处理程序实现的。(可能要等好久我才能记录到那个地方。)
打标签
第一个方法是打标签(tag),目的是将不明确的根里的所有非指针都与指针区别开来。打标签的方法很多,最基本的低1位作为标签的方法。
在32位cpu的情况下,指针的值是4的倍数,低2位一定是0,我们就利用这个特性。在前面提到引用1位计数法,这次我们使用它来识别指针和非指针。
- 打标签的具体方法:
- 将非指针int等,向左移1位(a << 1)
- 将低1位置位(a|1)
打标签的时候我们需要注意,比如在对数值打标签时,要注意不要让数据溢出。如果数据溢出,我们就得再变换一个更大的数据类型。
如果用这种方式打标签的话,所有数值都会是奇数。因此程序内进行计算时,必须取消标签位在计算。
基本上打标签和去标签都是语言处理程序完成的,这就是之前说的需要语言处理程序的帮助。
为不明确的根里的所有非指针打标签后,GC就能正确的识别指针和非指针了即正确识别指针。
不把寄存器和栈等当做根
不把寄存器和栈等不明确因素当做根,而是在处理程序里创建根。
具体来说就是,创建一个正确的根来管理,这个正确的根在处理程序里只集合了mutator可能到达的指针,然后以他为基础进行GC。
优点
首先,准确式GC完全没有保守式GC固有的问题--错误识别指针。此外它还可以实现GC复制算法等移动对象的算法。准确式GC可以正确的识别指针,所以即使移动对象,重写根这个对象也是正确的。
缺点
在创建语言处理程序时,必须照顾到GC。这会给实现算法带来一定的负担。在处理上也比较麻烦。
此外,创建正确的根就必须付出一定代价,比如说打标签。这实际关系到语言的处理速度。
间接引用
保守式 GC 有个缺点,就是“不能使用 GC 复制算法等移动对 象的算法”。解决这个问题的方法之一就是“间接引用”。
经由句柄引用对象
在保守式GC中有一个问题,无法使用垃圾回收算法。原因就是因为就不能明确的根,重写的对象有可能是非指针。
这个问题可以通过句柄(handle)来间接的处理对象。
从下图可以看出,根和对象之间有句柄。每个对象都有一个句柄,他们分别持有指向这些对象的指针。并且局部变量和全局变量这些不明确的对象的根里没有只想对象的指针,只装着指向句柄的指针。也就是说,有mutator操作对象时,要通过经由句柄的间接引用来执行处理。

采用句柄之后,就算是移动对象,也只需要修改句柄里的指针就行了。也就是说通过句柄间接访问对象。
在对象内没有经由句柄指向别的对象。只有在从根引用对象时,才会经由句柄。
使用间接引用的GC算法不是准确式GC。因为间接引用是以不明确的根为基础运行的GC,所以还不能正确识别指针和非指针。也就是说,还是会发生错误识别的情况。所以他也是保守式GC。

优缺点
优点:使用间接引用有可能实现GC复制算法,所以GC复制算法的优点就是它的优点。例如消除碎片化。
缺点:对象都经由句柄简介引用,所以会拉低访问内存对象的速度,这关系到整个语言处理程序的速度。
Conservative GC (Part one)的更多相关文章
- GC(Garbage Collection)
GC(Garbage Collection) GC背景 创建对象会消耗内存,如果不回收对象占用的内存,内存使用率会越来越高,最终出现OutOfMemoryError(OOM) 在C++中专 ...
- Conservative GC (Part two :MostlyCopyingGC )
目录 MostlyCopyingGC 概要 堆结构 分配 new_obj()函数 add_pages()函数 GC执行过程 mostly_copying()函数 promote_page()函数 pa ...
- C#.Net GC(garbage Collector) 垃圾回收器
以前一直以为gc的原理很简单,也就是分代处理堆数据,直到我的膝盖中了一箭(好吧 直到有天汪涛和我说他面试携程的面试题 关于服务器和 工作站gc 的区别)其实我当时尚不知道 工作站和服务器有什么区别更不 ...
- GC(Garbage Collection)垃圾回收机制
1.在垃圾回收器中,程序员没有执行权,只有通知它的权利. 2.程序员可以通过System.gc().通知GC运行,但是Java规范并不能保证立刻运行. 3.finalize()方法,是java提供给程 ...
- 浅析CLR的GC(垃圾回收器)
文章目录: 了解托管堆和GC GC高效的处理方式—代 特殊类型的清理 手动监控和控制对象生命周期 1.了解托管堆和GC 在面向对象环境中,每一个类型都代表了一种资源.我们要使用这些资源,就要为这些代表 ...
- Java GC(垃圾回收)机制知识总结
目录 Java GC系列 Java关键术语 Java HotSpot 虚拟机 JVM体系结构 Java堆内存 启动Java垃圾回收 Java垃圾回收过程 垃圾回收中实例的终结 对象什么时候符合垃圾回收 ...
- JVM——GC(垃圾回收)算法
一.垃圾回收的基本概念 垃圾回收(GC,Garbage Collection),指内存中不会再被使用的对象清理掉. 垃圾回收有很多种算法:如引用计数法.标记压缩法.复制算法.分代/分区的思想 二.垃圾 ...
- GC(垃圾回收)
Java程序的内存分配和回收都是由JRE在后台自动进行的.JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收GC.通常JRE会提供一条超级线程来进行检测和控制,一般都是在CPU空闲或内存不足时 ...
- 关于GC(垃圾回收)
当我用new创建一个对象时,当可分配的内存不足GC就会去回收未使用的对象,但是GC的操作是非常复杂的,会占用很多CPU时间,对于移动设备来说频繁的垃圾回收会严重影响性能.下面的建议可以避免GC频繁操作 ...
随机推荐
- Samurai's Stroke
题目链接 题意: 一个长度为L的木棍,有n个支点支撑,每一个点是一个int数.表示距离木棍左端点的距离.求在那些位置将木棍劈开能够使得至少有一个木棍掉下去,输出这些位置的长度 3 ≤ l ≤ 109; ...
- hadoop-12-安装ambari-agent
hadoop-12-安装ambari-agent 在所有的机器上面安装ambari-agent 1, cd /etc/yum.repos.d/vi 三个文件vi ambari.repo#VERSION ...
- LightOJ - 1038 Race to 1 Again 递推+期望
题目大意:给出一个数,要求你按一定的规则将这个数变成1 规则例如以下,如果该数为D,要求你在[1,D]之间选出D的因子.用D除上这个因子,然后继续按该规则运算.直到该数变成1 问变成1的期望步数是多少 ...
- 3、Python字典集合
2.3字典 字典是键值对的无序可变序列.键值之间用冒号隔开,相邻元素之间用逗号隔开,所有元素放在大括号之间{},键可以是Python中所有不可变的数据,不能用列表.元组.字典作为字典的键,键不可重复, ...
- js面向对象编程:怎样定义常量?
js中有一个keywordconst,但眼下的浏览器似乎还不支持,假设一定要定义一些常量,事实上能够使用闭包,匿名函数实现常量的定义. 比如: var Class = (function() { va ...
- CSS透明度设置支持IE,Chrome,Firefox浏览器
CSS文件里设置例如以下就可以 filter:alpha(opacity=60); //支持IE opacity:0.6; //支持Chrome.Firefox
- mvc中使用remote属性来做ajax验证
mvc中使用remote属性来做ajax验证比較easy : [Remote("Action", "Controller", AdditionalFields ...
- POJ 2528 Mayor's posters 离散化和线段树题解
本题就是要往墙上贴海报,问最后有多少可见的海报. 事实上本题的难点并非线段树,而是离散化. 由于数据非常大,直接按原始数据计算那么就会爆内存和时间的. 故此须要把数据离散化. 比方有海报1 6 7 ...
- Java 深拷贝和浅拷贝 利用序列化实现深拷贝
Java 深拷贝和浅拷贝 转自:http://www.cnblogs.com/mengdd/archive/2013/02/20/2917971.html 深拷贝(deep clone)与浅拷贝(sh ...
- Vue小技巧,如何导入普通JS文件
最近在开发一个展示3D模型的WEB程序,在工程中使用了VUE和ThreeJS库.Three.js本身是支持CommonJS的,但我们还用到了OBJLoader模块,此模块不支持CommonJS,改成C ...