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
}