在我写C++代码的那些时间里,我没有写过垃圾回收器,也没有实现过自己的内存分配器,这方面的文章倒是看了不 少。比如我在写C#代码时只管new而不需要释放,我也明白有个垃圾回收器在那帮我回收那些堆上的对象,但具体的实现也没有深究。这段时间我突然想起了以 前在某个地方看过关于一个小型垃圾回收器实现的文章,那是一篇翻译文章,于是搜了下找到了源代码,作者是Google公司一哥们(套近乎啊,好像认识似的)。今天韦哥决定分析一下这个实现,因为一般而言,分析比自己厉害得多的人的作品,总会有些收获。

源码在github上,顺藤摸瓜就能找到他解释这个实现的文章,点击这里:https://github.com/munificent/mark-sweep

这里为简单化,我们把变量使用的每一块内存都叫对象。我们知道,栈上的对象在函数调用过程中或者调用结束后全部被释放掉,可以理解为这是操作系统的ABI规
范,因此我们不需要管理栈内存,垃圾回收器管理的是堆内存。那垃圾回收器怎么知道哪些对象可以回收呢?应该是那些从栈上无法直接或间接访问到的堆上的对象可以被回收。那又怎么判定从栈上无法直接或间接访问到某个堆上对象呢?这也是我以前比较困惑的地方。比如我在某个函数里边写了一行:“A* p = new
A();”,在A对象产生的时候,应该在某个地方有个记录,保存了p的值。在函数退出时,记录里p的值被清理,但是它所指向的内存对象还存在,等到垃圾回收器进行回收检查的时候,它先要把能从栈上访问到的内存对象标记为被使用中,以免清理阶段错误释放了该内存对象。对于p,因为在记录里被清理了,在标记阶段,从栈上已经无法访问它,因此没有被标记为使用中,在清理阶段这个对象就会被释放掉。那么问题又来了,既然从栈上已经无法访问到p指向的对象,又如何释放呢?其实是有另外一个路径可以访问到它的,垃圾回收器保存一个根对象,通过这个根对象可以访问到所有已分配的内存对象,但这些对象可能已经没有栈上变量
指向它了,垃圾回收器正是以这个为依据来进行内存释放。

在作者的实现中,有两个结构体比较重要,就是虚拟机结构体,声明如下:

typedef struct {

Object* stack[STACK_MAX];
    int stackSize;
 
   /* The first object in the linked list of all objects on the heap. */
   Object* firstObject;
 
   /* The total number of currently allocated objects. */
   int numObjects;
 
   /* The number of objects required to trigger a GC. */
  int maxObjects;
 } VM;

从栈上能访问到的对象是那些从VM结构体中stack变量可以直接或间接访问到的对象,这里的对象就是Object类型的,Object声明如下:

typedef struct sObject {
    ObjectType type;
    unsigned char marked;

/* The next object in the linked list of heap allocated objects. */
   struct sObject* next;
 
   union {
     /* OBJ_INT */
     int value;
 
     /* OBJ_PAIR */
     struct {
       struct sObject* head;
       struct sObject* tail;
     };
   };

} Object;

Object结构体里有个next成员指向下一个对象,因此有间接访问到这么一说法。

VM结构体中stack变量决定了哪些对象还在被引用,比如上面提到的p,在刚刚给它分配对象时,从stack可以访问到它,但是当它离开所在作用域又没有其它变量引用过p所指向的内存对象时,从stack变量就已经无法访问到它了。但在p所指向内存对象被垃圾回收器释放之前,从VM结构体里的firstObject一步一步往下走,始终能找到这个内存对象。

顾名思义,mark-sweep算法分为两个阶段,即mark和sweep阶段,中文就是标记和清理阶段。有了以上的理解之后,我们就明白,这个实现中为什么在调用函数gc时依次调用了markAll(vm)和sweep(vm)。

void gc(VM* vm) {
   int numObjects = vm->numObjects;
 
   markAll(vm);
   sweep(vm);

vm->maxObjects = vm->numObjects * 2;

printf("\nCollected %d objects, %d remaining.\n", numObjects - vm->numObjects,
          vm->numObjects);
 }

每个Object对象有一个标记位,在这个对象初始化时标记为置0,表示可以被回收(是不是显得有点奇怪,会不会被错误释放?)。我刚开始直觉上也感觉不对,新对象不是在被使用吗,应该为1才对啊。而实际其思路是这样的:首先认为所有对象都可以被回收,然后在你回收之前,遍历stack变量,把从它能到达的对象都标记为1,这就是标记阶段,再执行清理,清理不再是遍历stack变量,而是遍历firstObject变量。对于那些遍历stack变量时因为没有直接或间接引用而不可达的变量,在清理阶段遍历firstObject却能找到它,并发现它的标记为是0,于是把它释放掉。对于那些标记为1的变量,把它重新置0回到初始状态,表示可回收,等待下次gc调用。

欢迎关注公众号:

使用mark-sweep算法的垃圾回收器的更多相关文章

  1. JVM 垃圾回收算法和垃圾回收器

    JVM 垃圾回收算法和垃圾回收器. 一.垃圾回收的区域 栈:栈中的生命周期是跟随线程,所以一般不需要关注. 堆:堆中的对象是垃圾回收的重点. 方法区:这一块也会发生垃圾回收,不过这块的效率比较低,一般 ...

  2. JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)

     相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题,有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制中的知识点呢?没时间捋也没关系,因为小编接下来会给你捋一捋. 一. 技术 ...

  3. java中的垃圾回收算法与垃圾回收器

    常用的垃圾回收算法 标记-清除 标记清除算法是一种非移动式的回收算法,分为标记 清除 2个阶段,简而言之就是先标记出需要回收的对象,标记完成后再回收掉所有标记的内存对象,如下图 可见回收后图中被标记的 ...

  4. Java垃圾回收算法和垃圾回收器

    基本上 jvm内存回收有三种 基本算法 标记-清除 标记清除的算法最简单,主要是标记出来需要回收的对象,然后然后把这些对象在内存的信息清除.如何标记需要回收的对象,在上一篇文章里面已经有说明. 标记- ...

  5. java架构之路-(12)JVM垃圾回收算法和垃圾回收器

    接上次JVM虚拟机堆内存模型来继续说,上次我们主要说了什么时候可能把对象直接放在老年代,还有我们的可能性分析,提出GCroot根的概念.这次我们主要来说说垃圾回收所使用的的算法和我们的垃圾回收器,需要 ...

  6. JVM——垃圾收集算法及垃圾回收器

    一.垃圾回收算法 1.标记-清除算法 1)工作流程 算法分为"标记"和"清除"阶段:首先标记出所有需要回收的对象(标记阶段),在标记完成后统一回收所有被标记的对 ...

  7. 一文了解JVM全部垃圾回收器,从Serial到ZGC

    <对象搜索算法与回收算法>介绍了垃圾回收的基础算法,相当于垃圾回收的方法论.接下来就详细看看垃圾回收的具体实现. 上文提到过现代的商用虚拟机的都是采用分代收集的,不同的区域用不同的收集器. ...

  8. 【转】Java学习---垃圾回收算法与 JVM 垃圾回收器综述

    [原文]https://www.toutiao.com/i6593931841462338062/ 垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的 ...

  9. 垃圾回收算法与 JVM 垃圾回收器综述(转)

    垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的回收方法.不同回收器的实现细节各有不同,但总的来说基本所有的回收器都会关注如下两个方面:找出所有的存 ...

随机推荐

  1. [luoguP1640] [SCOI2010]连续攻击游戏(二分图最大匹配)

    传送门 我们将每一个属性和物品连边,然后枚举从小到大属性跑匈牙利,直到找不到连边 #include <cstdio> #include <cstring> #include & ...

  2. Windows上安装DB2——从IBM官网得到90天试用版

    我在下面选的90天试用版: https://www.ibm.com/developerworks/cn/downloads/im/db2/ 进入下载页面,选择Windows https://www-0 ...

  3. 【NOI2017】游戏

    好久没写 $2-sat$ 了……(话说这东西哪里还考过) 题意 有 $3$ 种赛车 $A,B,C$ 和 $4$ 种赛道 $a,b,c,x$,赛车 $A$ 不适用于赛道 $a$,赛车 $B$ 不适用于赛 ...

  4. 深入浅出mysql全文随笔

    进入mysql :mysql -uroot -p 1.DDL(Data Definition Languages)语句:数据定义语言 2.DML(Data Manipulation Language) ...

  5. caffe编译新问题

    我在一台机子上,配置第二个caffe的时候,复制之前的Makefile文件,直接 make all 居然报错了报错如下 ndefined reference to cv::imread(cv::Str ...

  6. 如何应对pm2.5

    细颗粒物又称细粒.细颗粒.PM2.5:指环境空气中空气动力学当量直径小于等于 2.5 微米的颗粒物,也称细颗粒物.能较长时间悬浮于空气中,其在空气中含量(浓度)越高,就代表空气污染越严重.可吸入颗粒物 ...

  7. jquery中object对象循环遍历的方法

    一个朋友问对象如何转为数组,当我问他为啥要转得时候,他告诉我,数组可以用js循环遍历,而对象则不可以.其实呢,对象同样可以循环遍历的啊.不用转换也可以循环!说明你对js或者jquery的某些操作不是很 ...

  8. 洛谷P1469找筷子

    题目描述 经过一段时间的紧张筹备,电脑小组的“RP餐厅”终于开业了,这天,经理LXC接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题,筷子!CX ...

  9. 【NOIP2016游记】

    day-5:上午看了火箭打马刺 火箭差点翻盘但老大爷们还是稳 下午一场五校 T1T2原题做过 T3分块 day-4:上午五校1小时写3道暴力 2个半小时优化 然而还不知道拿了多少 %%%CC T2树链 ...

  10. vue.js源码学习分享(三)

    /** * Mix properties into target object.//把多个属性插入目标的对象 */ function extend (to, _from) { for (var key ...