Golang中如何追踪goroutine的内存分配情况

Golang中如何追踪goroutine的内存分配情况 我尝试使用 Go 运行时,以便在任何 Go 代码中无缝添加内存(字节、对象、分配调用)追踪功能。请在仓库 https://github.com/1pkg/gotcha 和博客文章 https://1pkg.github.io/posts/lets_trace_goroutine_allocated_memory/ 中查看详情。

1 回复

更多关于Golang中如何追踪goroutine的内存分配情况的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中追踪goroutine的内存分配情况,可以通过结合runtime包和自定义追踪器来实现。以下是一个示例代码,展示如何捕获每个goroutine的内存分配信息:

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

// 定义内存分配追踪器结构
type AllocTracker struct {
    mu      sync.Mutex
    allocs  map[uint64]uint64 // goroutine id -> 分配字节数
}

func NewAllocTracker() *AllocTracker {
    return &AllocTracker{
        allocs: make(map[uint64]uint64),
    }
}

// 开始追踪goroutine的内存分配
func (t *AllocTracker) Start() {
    go func() {
        for {
            t.mu.Lock()
            // 获取当前goroutine的ID(通过runtime.Stack)
            buf := make([]byte, 64)
            n := runtime.Stack(buf, false)
            stack := string(buf[:n])
            // 解析goroutine ID(简化示例,实际需更健壮的解析)
            var goroutineID uint64
            fmt.Sscanf(stack, "goroutine %d", &goroutineID)
            
            // 获取当前goroutine的内存分配统计
            var memStats runtime.MemStats
            runtime.ReadMemStats(&memStats)
            t.allocs[goroutineID] = memStats.TotalAlloc
            
            t.mu.Unlock()
            time.Sleep(100 * time.Millisecond) // 每100ms采样一次
        }
    }()
}

// 获取指定goroutine的分配内存(字节)
func (t *AllocTracker) GetAlloc(goroutineID uint64) uint64 {
    t.mu.Lock()
    defer t.mu.Unlock()
    return t.allocs[goroutineID]
}

func main() {
    tracker := NewAllocTracker()
    tracker.Start()
    
    var wg sync.WaitGroup
    wg.Add(2)
    
    // 启动示例goroutine
    go func() {
        defer wg.Done()
        // 模拟内存分配
        data := make([]byte, 1024*1024) // 分配1MB
        _ = data
        time.Sleep(500 * time.Millisecond)
        // 输出当前goroutine分配内存
        fmt.Printf("Goroutine 1 allocated: %d bytes\n", tracker.GetAlloc(1))
    }()
    
    go func() {
        defer wg.Done()
        // 模拟更多内存分配
        for i := 0; i < 10; i++ {
            _ = make([]byte, 512*1024) // 每次分配512KB
            time.Sleep(50 * time.Millisecond)
        }
        fmt.Printf("Goroutine 2 allocated: %d bytes\n", tracker.GetAlloc(2))
    }()
    
    wg.Wait()
}

此代码创建了一个内存分配追踪器,周期性采样各goroutine的内存分配情况。通过runtime.Stack获取goroutine ID,并结合runtime.ReadMemStats读取内存统计。注意:实际应用中需要更精确的goroutine ID解析,且频繁采样可能影响性能。

对于更细粒度的控制,可参考runtime.MemProfileRate设置内存剖析速率,或使用pprof工具进行深度分析。

回到顶部