go里面的垃圾回收是如何进行的(2)?

学习好一门语言贵在坚持!

首先:

博主是👦一个帅气的boy,你可以叫我山鱼君
🖱 ⌨个人主页:山鱼君的个人主页
💖💖如果对你有帮助的话希望三连下⭐⭐⭐支持一下博主🌊

图片说明

精确的垃圾回收

像C语言这种不支持垃圾回收的语言,其实还是有些垃圾回收的库可以使用的。这类库一般也是用的标记清扫算法实现的,但是它们都是保守的垃圾回收。之所以叫“保守”是因为它们没办法获取对象类型信息,因此只能保守地假设地址区间中每个字都是指针。

无法获取对象的类型信息会造成什么问题呢?这里举个例子来说明。

假设某个结构体中是不包含指针成员的,那么对该结构体成员进行垃圾回收时,其实是不必要递归地标记结构体的成员的。但是由于没有类型信息,我们并不知道这个结构体成员不包含指针,因此我们只能对结构体的每个字节递归地标记下去,这显然会浪费很多时间。这个例子说明精确的垃圾回收可以减少不必要的扫描,提高标记过程的速度。

这个例子说明,保守的垃圾回收某些情况下会出现垃圾无法被回收的情况。虽然不会造成大的问题,但总是让人很不爽,都是没有类型信息惹的祸。

现在好了,在Go语言的 1.1 版本中开始支持精确的垃圾回收。精确的垃圾回收首先需要的就是类型信息,上一节中讲过 MSpan 结构体,类型信息是存储在 MSpan 中的。从一个地址计算它所属的 MSpan,公式如下:

页号 = (地址 - mheap.arena_start) >> 页大小
MSpan = mheap->map[页号]

1.接下来通过 MSpan->type 可以得到分配块的类型。这是一个 MType 的结构体:

struct  MTypes
{
    byte         compression;         //  one  of  MTypes_*
    bool         sysalloc;            //  whether  (void*)data  is  from  runtime·SysAlloc uintptr         data;
};

2.MTypes

MTypes 描述 MSpan 里分配的块的类型,其中 compression 域描述数据的布局。它的取值为 MTypes_Empty、MTypes_Single、MTypes_Words、MTypes_Bytes 四个中的一种:
MTypes_Empty:所有的块都是 free 的,或者这个分配块的类型信息不可用。这种情况下 data 域是无意义的。
MTypes_Single:这个 MSpan 只包含一个块,data 域存放类型信息,sysalloc 域无意义。
MTypes_Words:这个 MSpan 包含多个块(块的种类多于 7)。这时 data 指向一个数组 [NumBlocks]uintptr,数组里每个元索存放相应块的类型信息。
MTypes_Bytes:这个 MSpan 中包含最多 7 种不同类型的块。这时 data 域指下面这个结构体

struct  {
    type    [8]uintptr               //  type[0]  is  always  0
    index   [NumBlocks]byte
}

第 i 个块的类型是 data.type[data.index[i]]

表面上看 MTypes_Bytes 好像最复杂,其实这里的复杂程度是 MTypes_Empty 小于 MTypes_Single 小于 MTypes_Bytes 小于 MTypes_Words 的。MTypes_Bytes 只不过为了做优化而显得很复杂。

上一节中说过,每一块 MSpan 中存放的块的大小都是一样的,不过它们的类型不一定相同。如果没有使用,那么这个 MSpan 的类型就是 MTypes_Empty。如果存一个很大块,大于这个 MSpan 大小的一半,因此存不了其它东西了,那么这个 MSpan 的类型是 MTypes_Single。

假设存了多种块,每一块用一个指针,本来可以直接用 MTypes_Words 存的。但是当类型不多时,可以把这些类型的指针集中起来放在数组中,然后存储数组索引。这是一个小的优化,可以节省内存空间。

得到的类型信息最终其实是一个这样的结构体:

struct  Type
{
    uintptr  size;
    uint32  hash;
    uint8  _unused;
    uint8  align;
    uint8  fieldAlign;
    uint8  kind;
    Alg  *alg;
    void  *gc;
    String  *string;
    UncommonType  *x;
    Type  *ptrto;
};

不同类型的类型信息结构体略有不同,这个是通用的部分。可以看到这个结构体中有一个 gc 域,精确的垃圾回收就是利用类型信息中这个 gc 域实现的。

图片说明

最后:
✨原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 原创不易,还希望各位大佬支持一下
点赞👍:您的赞赏是我前进的动力!
收藏⭐:您的支持我是创作的源泉!
评论✍:您的建议是我改进的良药!

#go语言##快乐学习#
全部评论
之前我差点从事go了
点赞 回复 分享
发布于 2022-08-18 21:11 陕西

相关推荐

2025-12-15 14:25
云南大学 Java
lei22:入职可能会看学信网,最好别伪装,这个简历找实习肯定是够的,肯定会有收 28 届实习生的公司的,多投就行
点赞 评论 收藏
分享
评论
4
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务