Go语言内存机制 | 青训营笔记

71 阅读4分钟

Go语言内存机制

这是我参加「第五届青训营」伴学笔记创作活动的第 4 天

垃圾回收

Go语言的内存机制是通过垃圾回收来实现的。

Go语言中的垃圾回收采用了标记-清除算法,这种算法会标记出那些还在使用中的变量,然后清除掉那些没有标记的变量。

Go语言中的垃圾回收器是自动运行的,开发者不需要手动调用。

下面是一个简单的示例代码,这段代码中的变量x和y都是在堆上分配的,当main函数运行完后,x和y都会被垃圾回收器回收。

 package main
 ​
 import "fmt"
 ​
 func main() {
     x := 1
     y := 2
     fmt.Println(x + y)
 }

Go语言中的变量分为两种:堆上的变量和栈上的变量。

堆上的变量是通过new或者make来分配内存的,这种变量的生命周期是由垃圾回收器来管理的。

栈上的变量是直接在栈上分配内存的,这种变量的生命周期是由编译器来管理的。

在Go语言中,我们可以通过调用runtime.GC()来显示触发垃圾回收,但是一般不建议这么做,因为Go语言的垃圾回收器是自动调整回收频率的,手动触发垃圾回收可能会导致性能问题。

需要注意的是,Go语言中的垃圾回收器并不能管理所有的内存,如果程序中使用了大量的 CGO,或者使用了大量的第三方库,那么就需要开发者自己来管理这部分的内存。

引用计数

在Go语言中,还有一个很重要的概念就是“引用计数”,这是一种跟踪变量使用次数的方法。当变量被引用时,它的引用计数就会增加1,当变量不再被引用时,它的引用计数就会减少1。只有当一个变量的引用计数变为0时,这个变量才会被垃圾回收器回收。

下面是一个示例代码,这段代码中有两个指针变量p1p2,它们都指向了一个堆上的变量。在main函数结束时,这个堆上的变量会被回收,因为它的引用计数变为了0

 package main
 ​
 import "fmt"
 ​
 func main() {
     x := new(int)
     *x = 1
     p1 := x
     p2 := x
     p1 = nil
     p2 = nil
     fmt.Println(*x)
 }
 ​

引用计数用来跟踪变量使用次数。通过这种方式,Go语言可以有效地管理内存,避免内存泄漏和内存溢出。使用Go语言编程时,开发者不需要过多关注内存管理,只需要了解基本的概念和使用方法即可。

池化

此外,Go语言还提供了一种叫做“池化”的内存管理技术。池化技术可以在程序运行过程中预先申请一些内存,然后将这些内存按照需求分配给程序使用。这样可以减少程序在运行过程中频繁申请和释放内存的次数,提高程序的性能。

Go语言中的“池化”技术主要通过sync.Pool来实现。使用sync.Pool可以预先申请一些内存块,然后在程序运行过程中按需分配。下面是一个简单的示例代码,这段代码中使用了sync.Pool来管理内存。

 package main
 ​
 import (
     "fmt"
     "sync"
 )
 ​
 func main() {
     var pool = &sync.Pool{
         New: func() interface{} {
             return new(int)
         },
     }
     for i := 0; i < 10; i++ {
         p := pool.Get().(*int)
         *p = i
         fmt.Println(*p)
         pool.Put(p)
     }
 }
 ​

需要注意的是,使用池化技术需要在程序设计上进行一些特殊的考虑,比如对象的类型和生命周期需要与池化对象相匹配。

工具

另外, Go语言中提供了一些工具和接口来帮助开发者管理内存,比如:

  • runtime.MemStats结构体可以用来获取Go程序的内存使用情况
  • debug.FreeOSMemory()函数可以用来立即释放系统中未使用的内存

下面是一个示例代码,这段代码中使用了runtime.MemStats结构体来获取Go程序的内存使用情况。

 package main
 ​
 import (
     "fmt"
     "runtime"
 )
 ​
 func main() {
     var mem runtime.MemStats
     runtime.ReadMemStats(&mem)
     fmt.Printf("Alloc = %v MiB", mem.Alloc / 1024 / 1024)
 }