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频繁操作 ...
随机推荐
- c++_benchMark_vector_list_deque
title: c++_benchMark_vector_list_deque date: 2015-08-01 22:32:39 作者:titer1 + ZhangYu 出处:www.drysalte ...
- 第九章 TCP和UDP同一时候用复用一个port实现一个回射server
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include &l ...
- 配置ssh免密码登录的原理
- Hadoop 框架基础(四)
** Hadoop 框架基础(四) 上一节虽然大概了解了一下 mapreduce,徒手抓了海胆,不对,徒手写了 mapreduce 代码,也运行了出来.但是没有做更深入的理解和探讨. 那么…… 本节目 ...
- bootstrap-treeview简单使用
废话不多说,直接上干干货. 1.bootstrap-treeview Github网址:https://github.com/jonmiles/bootstrap-treeview 2.使用要求: & ...
- vue中使用console.log无效
webpack开发环境下,在vue中使用console.log无效,一直以为webpack出了问题. 使用window.console.log()就能够顺利在浏览器控制台输出了. 以及 在axios请 ...
- bzoj2100 [Usaco2010 DEC]Apple Delivery苹果贸易
题目描述 一张P个点的无向图,C条正权路.CLJ要从Pb点(家)出发,既要去Pa1点NOI赛场拿金牌,也要去Pa2点CMO赛场拿金牌.(途中不必回家)可以先去NOI,也可以先去CMO.当然神犇CLJ肯 ...
- WHU 1540 Fibonacci 递推
武大邀请赛的网络预选赛,就去做了个签到题,居然连这个递推都没推出来,真是惭愧. 而且好久没写矩阵乘法了,来回顾一下. 题意: 求Fibonacci数列的,前n项立方和. 思路: 可以求得一下递推公式: ...
- 【Codeforces Round #420 (Div. 2) C】Okabe and Boxes
[题目链接]:http://codeforces.com/contest/821/problem/C [题意] 给你2*n个操作; 包括把1..n中的某一个数压入栈顶,以及把栈顶元素弹出; 保证压入和 ...
- Ehcache学习总结(1)--Ehcache入门介绍
Ehcache是现在最流行的纯Java开源缓存框架,配置简单.结构清晰.功能强大,最初知道它,是从hibernate的缓存开始的.网上中文的EhCache材料以简单介绍和配置方法居多,如果你有这方面的 ...