68个spanClass

68个spanClass

68个spanClass #

在 Go 的三级内存管理器中,维护的对象都是小于 32KB 的小对象。对于这些小对象,Go 又将其按照大小分成了 67 个类别,称为 spanClass。每一个 spanClass 都用来存储固定大小的对象。这 67 个 spanClass 的信息在 runtime.sizeclasses.go 中可以看到详细的说明。

// class  bytes/obj  bytes/span  objects  tail waste  max waste  min align
//     1          8        8192     1024           0     87.50%          8
//     2         16        8192      512           0     43.75%         16
//     3         24        8192      341           8     29.24%          8
//     4         32        8192      256           0     21.88%         32
//    ...
//    67      32768       32768        1           0     12.50%       8192

class 3 是说在 spanClass 为 3 的 span 结构中,存储的对象的大小是 24 字节,整个 span 的大小是 8192 字节,也就是一个内存页的大小,可以存放的对象数目最多是 341。

tail waste 这里是 8 字节,这个 8 是通过 8192 mod 24 计算得到,意思是,当这个 span 填满了对象后,会有 8 字节大小的外部碎片。而 max waste 的计算方式则是 [(24−17)×341+8]÷8192 得到,意思是极端场景下,该 span 上分配的所有对象大小都是 17 字节,此时的内存浪费率为 29.24%。

以上 67 个存储小对象的 spanClass 级别,再加上 class 为 0 时用来管理大于 32KB 对象的 spanClass,共总是 68 个 spanClass。

这些数据都是通过在 runtime.mksizeclasses.go 中计算得到的。Go 在分配的时候,是通过控制每个 spanClass 场景下的最大浪费率,来保障堆内存在 GC 时的碎片率的。

Viewpoint #

From #

24 | GC实例:Python和Go的内存管理机制是怎样的?