golang服务发生高内存高cpu排查分析总结

1.记录内存和cpu文件

        memProfileTicker := time.NewTicker(5 * time.Second) // 每分钟收集一次内存信息
        defer memProfileTicker.Stop()

        go func() {
                for range memProfileTicker.C {
                        // CPU Profile
                        cpuf, err := os.Create("cpu.pprof")
                        if err != nil {
                                fmt.Printf("could not create CPU profile: %v\n", err)
                        }
                        defer cpuf.Close()

                        if err := pprof.StartCPUProfile(cpuf); err != nil {
                                fmt.Printf("could not start CPU profile: %v\n", err)
                        }
                        defer pprof.StopCPUProfile()

                        memf, err := os.Create("mem.pprof")
                        if err != nil {
                                fmt.Printf("could not create memory profile: ", err)
                        }
                        defer memf.Close() // 错误处理略

                        runtime.GC() // 获取最新的内存统计信息

                        if err := pprof.WriteHeapProfile(memf); err != nil {
                                fmt.Printf("could not write memory profile: ", err)
                        }
                }
        }()

实测内存可以有效记录,cpu文件没有变化,于是用下列代码替代

        // 用于记录CPU分析文件的计数器
        fileCounter := 0
        ticker := time.NewTicker(5 * 60 * time.Second)
        defer ticker.Stop()

        go func() {
                for {
                        select {
                        case <-ticker.C:
                                fileCounter++
                                fileName := fmt.Sprintf("cpu_%d.prof", fileCounter)
                                f, err := os.Create(fileName)
                                if err != nil {
                                        app.lc.Errorf("无法创建CPU性能分析文件,错误:%s", err.Error())
                                        continue
                                }
                                pprof.StartCPUProfile(f)
                                // 这里设置一个延迟,让CPU分析收集一小段时间的数据,比如收集3分钟的数据
                                time.Sleep(3 * 60 * time.Second)
                                pprof.StopCPUProfile()
                                f.Close()
                        }
                }
        }()

2.分析pprof文件

go tool pprof -http=:6090 mem.pprof

3.经排查内存占比高,是因为程序集成lua脚本(“github.com/yuin/gopher-lua”)

func (pl *LStatePool) Get() *lua.LState {
	pl.m.Lock()
	defer pl.m.Unlock()
	n := len(pl.saved)
	if n == 0 {
		return pl.New()
	}
	x := pl.saved[n-1]
	pl.saved = pl.saved[0 : n-1]
	return x
}

高并发模式下,LStatePool数量会无限创建导致内存增长。
可以采用如下两种方法解决:

func (pl *LStatePool) Get() *lua.LState {
	pl.m.Lock()
	defer pl.m.Unlock()
	return pl.New()
}
func (pl *LStatePool) Get() *lua.LState {
	pl.m.Lock()
	defer pl.m.Unlock()
	n := len(pl.saved)
	if n == 0 {
		if len(pl.saved) < 40 {
			return pl.New()
		}
		time.Sleep(10 * time.Millisecond)
		return pl.Get()
	}
	x := pl.saved[n-1]
	pl.saved = pl.saved[0 : n-1]
	return x
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值