Golang 中的内存分配(memory allocation)机制是怎样的?

在 Golang 中,内存分配主要由运行时(runtime)完成。Golang 使用自己的内存分配器管理内存,而不是操作系统的 malloc。

Golang 的内存分配机制主要有:

  1. 指针区(pointer bitmap):Golang 将内存按页(通常4KB或8KB)分割,每一页都有一个指针区,用于记录页内已分配和未分配的内存块。这使得内存分配和回收可以清晰可控。
  2. 小对象分配:对于较小的对象(小于32KB),Golang 会将它们存放在特定的页内。如果一页剩余空间不足以存放新对象,则会找到或分配一个新的页。这可以避免外部碎片。
  3. 大对象分配:对于较大的对象(大于32KB),Golang 会直接从操作系统处申请一块新的内存,并存放该对象。
  4. 空闲列表:Golang 维护着一个空闲页列表和空闲对象列表,这使得内存回收后的内存块可以被快速重用。
  5. 断言式内存回收(Non-Generational GC):Golang 使用并发的标记-清除(mark-sweep) GC算法来回收垃圾内存。在回收时,GC会停止所有的 goroutine,扫描整个内存找出所有可达对象,然后回收掉不可达对象所占的内存。

例如:

type User struct {
    name string
}

func main() {
    u1 := new(User)   // 分配User大小的内存,并返回指针
    u2 := User{"John"}   // 在栈上分配

    u3 := make([]int, 10)   // 分配切片,在堆上分配内存
}  
  • u1 分配在堆上,由Golang的内存分配器管理,new() 函数返回指向对象的指针。
  • u2 分配在栈上,由操作系统自动回收。
  • u3 切片也分配在堆上,由Golang的内存分配器管理。

Golang 的内存分配器设计巧妙,利用指针区域、小对象特殊分配与空闲列表等手段提高了内存分配效率和空间利用率。配合并发标记清除型的GC,可以有效回收垃圾内存。这使得 Golang 可以高效地管理程序所需的内存,这也是它作为系统语言的重要保障之一。

所以 Golang 的内存分配机制与其并发GC算法使得它可以更加高效和准确地管理内存。这为 Golang 程序带来的低延时与高稳定性提供了重要基石。深入理解 Golang 的内存管理机制,有助于我们编写出更加优雅和高性能的程序。这也可以帮助我们更好地解决一些常见的内存管理与性能优化问题。