Go 内存分配器的设计与实现( 十 )


func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { ... if size <= maxSmallSize {... } else {var s *mspansystemstack(func() {s = largeAlloc(size, needzero, noscan)})s.freeindex = 1s.allocCount = 1x = unsafe.Pointer(s.base())size = s.elemsize } publicationBarrier() mp.mallocing = 0 releasem(mp) return x}runtime.largeAlloc 函数会计算分配该对象所需要的页数,它会按照 8KB 的倍数为对象在堆上申请内存:
func largeAlloc(size uintptr, needzero bool, noscan bool) *mspan { npages := size >> _PageShift if size&_PageMask != 0 {npages++ } ... s := mheap_.alloc(npages, makeSpanClass(0, noscan), needzero) s.limit = s.base() + size heapBitsForAddr(s.base()).initSpan(s) return s}申请内存时会创建一个跨度类为 0 的 runtime.spanClass 并调用 runtime.mheap.alloc 分配一个管理对应内存的管理单元 。
小结内存分配是 Go 语言运行时内存管理的核心逻辑,运行时的内存分配器使用类似 TCMalloc 的分配策略将对象根据大小分类,并设计多层级的组件提高内存分配器的性能 。本节不仅介绍了 Go 语言内存分配器的设计与实现原理,同时也介绍了内存分配器的常见设计,帮助我们理解不同编程语言在设计内存分配器时做出的不同选择 。
内存分配器虽然非常重要,但是它只解决了如何分配内存的问题,我们在本节中省略了很多与垃圾回收相关的代码,没有分析运行时垃圾回收的实现原理,在下一节中我们将详细分析 Go 语言垃圾回收的设计与实现原理 。
延伸阅读

  • The Go Memory Model
  • A visual guide to Go Memory Allocator from scratch (Golang)
  • TCMalloc : Thread-Caching Malloc
  • Getting to Go: The Journey of Go's Garbage Collecton
  • Go: Memory Management and Allocation




推荐阅读