Skip to content

7.1 内存管理 ​

内存分配机制 ​

Go 内存分配器 (基于 tcmalloc):

内存层次:
1. sync.Pool - 对象池 (最快)
2. mspan - 小对象分配 (2KB - 32KB)
3. mheap - 大对象分配 (>32KB)
4. mmap - 直接向系统申请

分配策略:
- 小对象 (< 32KB): 从 mspan 分配
- 大对象 (> 32KB): 直接从 mheap 分配
- 超大对象 (> 32MB): 直接向系统 mmap

逃逸分析:
- 编译器决定变量分配在栈上还是堆上
- 栈分配更快,自动释放
- 堆分配需要 GC

查看内存统计 ​

go
import "runtime"

func printMemStats() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)

    fmt.Printf("Alloc = %v KB\n", m.Alloc/1024)
    fmt.Printf("TotalAlloc = %v KB\n", m.TotalAlloc/1024)
    fmt.Printf("Sys = %v KB\n", m.Sys/1024)
    fmt.Printf("NumGC = %v\n", m.NumGC)
}

减少内存分配 ​

go
// 不好:循环内分配
func badAlloc() []byte {
    var result []byte
    for i := 0; i < 1000; i++ {
        result = append(result, make([]byte, 100)...)
    }
    return result
}

// 好:预设容量
func goodAlloc() []byte {
    result := make([]byte, 0, 1000*100)
    for i := 0; i < 1000; i++ {
        // 使用预分配的容量
    }
    return result
}

// 使用 sync.Pool
var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 1024)
    },
}

func usePool() {
    buf := bufferPool.Get().([]byte)
    defer bufferPool.Put(buf)
    // 使用 buf
}

逃逸分析 ​

go
// 逃逸到堆
func escapeToHeap() *int {
    x := 42
    return &x  // x 逃逸到堆上
}

// 不逃逸 (栈分配)
func noEscape() int {
    x := 42
    return x
}

// 闭包捕获 (逃逸)
func closureEscape() func() int {
    x := 42
    return func() int {
        return x
    }
}

// 查看逃逸分析
// go build -gcflags="-m" main.go

垃圾回收 (GC) ​

GC 算法 (并发标记 - 清扫):

GC 阶段:
1. 标记准备 (STW, 短暂)
2. 并发标记 (应用程序继续运行)
3. 标记结束 (STW, 短暂)
4. 并发清扫 (应用程序继续运行)

GC 调优:
1. 调整 GOGC (默认 100)
   export GOGC=50   # 更频繁 GC,更低内存
   export GOGC=200  # 更少 GC,更高内存

2. 减少分配
   - 预设容量
   - 对象复用
   - 避免逃逸

3. 使用 sync.Pool

内存优化技巧 ​

go
// 1. 字符串拼接
// 不好:O(n²)
func badConcat(parts []string) string {
    result := ""
    for _, p := range parts {
        result += p
    }
    return result
}

// 好:使用 strings.Builder
func goodConcat(parts []string) string {
    var sb strings.Builder
    for _, p := range parts {
        sb.WriteString(p)
    }
    return sb.String()
}

// 2. Map 预分配
m := make(map[int]int, 1000)

// 3. 零拷贝
func zeroCopy(data []byte, start, end int) []byte {
    return data[start:end]
}

// 4. 结构体字段对齐 (按大小排序)
type GoodStruct struct {
    B int64  // 8 bytes
    A bool   // 1 byte
    C bool   // 1 byte
}  // 16 bytes