【Go语言的垃圾回收机制(2)】

简介: 【Go语言的垃圾回收机制(2)】

精确的垃圾回收


像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新生肯定会有很大的帮助滴。不要着急,不要慌,月亮下面有月光,循着月光找月亮,🌜🌜🌜快来🐂牛客🐂吧!

目录
相关文章
|
15天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
26 7
|
15天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
15天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
92 71
|
14天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
100 67
|
15天前
|
存储 Go
go语言中映射
go语言中映射
32 11
|
16天前
|
Go 索引
go语言修改元素
go语言修改元素
25 6
|
7天前
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数
|
17天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
88 62
|
19天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
17天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
29 12