go 内存分配

关注 go 语言内存分配策略,主要是想了解 go 的性能。申请不同大小的内存,性能开销是有差别的,申请内存越大,耗时也越久,性能也越差。

内存分配

参考 Go1.17.13 版本源码,从内存分配大小上区分了 tiny、small、large 3种对象类型,具体实现细节在函数 mallocgc
中。代码的逻辑结构如下:

if size <= maxSmallSize {
	if noscan && size < maxTinySize {
	} else {
	}
} else {
}

small 和 large 的区分标准是 32kb,小于等于 32kb 都属于 small 对象,而 tiny 需要小于 16byte。tiny 内存分配还限制了对象类型, noscan 用来标识对象中不包含指针类型。

小对象的申请

小对象的申请比较简单,下面这几行源码可以清晰的描述流程:c 表示当前的 mcache,首先计算小对象对应的 spanClass,然后尝试获取对应 span 链表中第一个空内存块,如果获取失败,尝试通过 nextFree 获取。

	size = uintptr(class_to_size[sizeclass])
	spc := makeSpanClass(sizeclass, noscan)
	span = c.alloc[spc]
	v := nextFreeFast(span)
	if v == 0 {
		v, span, shouldhelpgc = c.nextFree(spc)
	}

c.alloc 是长度为 136 的数组类型,每个 sizeclass 分别对应了 noscan 和 scan 两种类型的内存分配。通过函数 makeSpanClass 可以计算出 alloc 数组的下标,同类型的 noscan、scan 交替出现。

func makeSpanClass(sizeclass uint8, noscan bool) spanClass {
	return spanClass(sizeclass<<1) | spanClass(bool2int(noscan))
}
  • 逃逸分析反思
  • go size class 内存分配思考
  • Go参考TcMalloc内存分配

你可能感兴趣的:(Go学习理解,golang,开发语言,后端)