模拟Golang应用内存泄漏的示例程序

package main

import (
	"github.com/pyroscope-io/client/pyroscope"
	"log"
	"os"
	"runtime"
	"time"
)

type demo struct {
	slice []byte
}

var demos = make([]*demo, 0, 1024)
var demosNormal = make([]*demo, 0, 1024)
var beforeTime time.Time

func main() {
	runtime.SetBlockProfileRate(100)
	runtime.SetMutexProfileFraction(100)
	serverAddress := os.Getenv("PYROSCOPE_SERVER_ADDRESS")
	if serverAddress == "" {
		serverAddress = "http://localhost:4040"
	}
	appName := os.Getenv("PYROSCOPE_APPLICATION_NAME")
	if appName == "" {
		appName = "go-leak-app"
	}

	_, err := pyroscope.Start(pyroscope.Config{
		ApplicationName: appName,
		ServerAddress:   serverAddress,
		AuthToken:       os.Getenv("PYROSCOPE_AUTH_TOKEN"),
		Logger:          pyroscope.StandardLogger,
		Tags:            map[string]string{"hostname": os.Getenv("HOSTNAME"), "environment": "test", "version": "1.0"},
	})
	if err != nil {
		log.Fatalf("error starting pyroscope profiler: %v", err)
	}

	for {
		memNormal()
		memLeak()
		time.Sleep(time.Second)
	}
}

func memNormal() {
	if len(demosNormal) > 600 {
		time.Sleep(time.Nanosecond)
		return
	}
	demosNormal = append(demosNormal, &demo{
		slice: make([]byte, 4000),
	})
}

func memLeak() {
	now := time.Now()
	if now.Sub(beforeTime).Minutes() > 60 {
		demos = make([]*demo, 0, 1024)
		println("clear cache data")
		beforeTime = now
	}
	demos = append(demos, &demo{
		slice: make([]byte, 4000),
	})
}

该段代码包含三部分:

  • main函数:程序的入口,每秒执行一次memNormal函数与memLeak函数。main函数中还包含性能监控接入代码。

  • memNormal函数:模拟正常程序运行。在程序运行的前10分钟内,每秒增加4000字节内存;在后续时间段内,不再额外增加内存。

  • memLeak函数:模拟内存泄漏情景。在程序运行的所有时间内,每秒增加4000字节内存。

    模拟程序以1小时为1个周期,周期结束后将释放所有内存。

问题发现与排查过程

本排查过程基于上述示例程序的数据。

通过数据查询进行排查

您可以通过性能监控>数据查询页面,排查问题。更多信息,请参见数据查询。

service:golang_leak_applanguage:gotype:profile_memvalueTypes:inuse_space

通过数据对比进行排查

您在数据查询页面,单击快速对比后,系统将同步您已完成的配置(元数据筛选条件、标签筛选条件、聚合策略、元数据时间范围、主时间范围)到数据对比页面。更多信息,请参见数据对比。

  1. 设置预设同比时间为过去30min

  2. 观察并聚焦memNormal函数与memLeak函数的具体变化。image.pngimage.png

通过上述对比可知memNormal函数过去和现在的内存没有变化,但是占用总内存比例却减少了38%,同时memLeak函数的当前值比过去半小时的值涨了0.43 GB内存,占用总内存比例增加了37%。