英文:
Unable to release memory bytes buffer
问题
Go 1.18.1
pprof报告
 3549.93kB 49.73% 49.73%  3549.93kB 49.73%  src/lag_monitor.PublishLagMetricToDataDog
     514kB  7.20% 56.93%      514kB  7.20%  bufio.NewWriterSize
  512.88kB  7.18% 64.11%   512.88kB  7.18%  encoding/pem.Decode
  512.69kB  7.18% 71.30%  1536.98kB 21.53%  crypto/x509.parseCertificate
  512.50kB  7.18% 78.48%   512.50kB  7.18%  crypto/x509.(*CertPool).AddCert
这段代码似乎没有释放内存,根据pprof的结果,下面的函数是消耗最多内存的函数。内存图如下:
func caller() {
	events := make([]string, 0)
	//....
	PublishLagMetricToDataDog(ctx, strings.Join(events, ","))
}
func PublishLagMetricToDataDog(ctx context.Context, events string) error {
	msg := `{
		"series": [%v]
	}`
	b := []byte(msg)
	resp, err := http.Post("https://api.datadoghq.com/api/v1/series?api_key="+env.GetDataDogKey(), "application/json", bytes.NewBuffer(b))
	if err != nil {
		logger.Error(ctx, "Error submitting event to datadog, err =", err)
		return err
	}
	logger.Info(ctx, resp)
	return nil
}
上述函数在一个循环中被调用。由于没有全局变量,并且没有对来自PublishLagMetricToDataDog的字节切片的引用,我无法确定内存泄漏的位置。我了解了Reset()和Truncate(),但这些方法并不能释放底层内存。
英文:
Go 1.18.1
pprof report
 3549.93kB 49.73% 49.73%  3549.93kB 49.73%  src/lag_monitor.PublishLagMetricToDataDog
     514kB  7.20% 56.93%      514kB  7.20%  bufio.NewWriterSize
  512.88kB  7.18% 64.11%   512.88kB  7.18%  encoding/pem.Decode
  512.69kB  7.18% 71.30%  1536.98kB 21.53%  crypto/x509.parseCertificate
  512.50kB  7.18% 78.48%   512.50kB  7.18%  crypto/x509.(*CertPool).AddCert
This piece of code appears to not release memory and based on pprof, the beloew function is the one consuming most memory.Memory graph

func caller() {
 events := make([]string, 0)
 //....
 PublishLagMetricToDataDog(ctx, strings.Join(events, ","))
}
func PublishLagMetricToDataDog(ctx context.Context, events string) error {
msg := `{
	"series": [%v]
}`
b := []byte(msg)
resp, err := http.Post("https://api.datadoghq.com/api/v1/series?api_key="+env.GetDataDogKey(), "application/json", bytes.NewBuffer(b))
if err != nil {
	logger.Error(ctx, "Error submitting event to datadog, err = ", err)
	return err
}
logger.Info(ctx, resp)
return nil
}
Above function is called in a loop. Since there are no global variables, and no reference to the byte slice from PublishLagMetricToDataDog, I am not able to pinpoint the memory leak. I read about Reset() and Truncate(), but this does not release the underlying memory.
答案1
得分: 2
你必须关闭每个收到的 HTTP 响应的响应体。如果不这样做,可能会导致资源泄漏,就像你观察到的那样。
解决方案:
    resp, err := http.Post("https://api.datadoghq.com/api/v1/series?api_key="+env.GetDataDogKey(), "application/json", bytes.NewBuffer(b))
    if err != nil {
        logger.Error(ctx, "Error submitting event to datadog, err =", err)
        return err
    }
    logger.Info(ctx, resp)
    _ = resp.Body.Close() // <--- 添加这行代码
    return nil
}
英文:
You must close the response body for every http response you receive. Not doing so will potentially lead to resource leaks, such as the one you've observed.
Solution:
    resp, err := http.Post("https://api.datadoghq.com/api/v1/series?api_key="+env.GetDataDogKey(), "application/json", bytes.NewBuffer(b))
    if err != nil {
        logger.Error(ctx, "Error submitting event to datadog, err = ", err)
        return err
    }
    logger.Info(ctx, resp)
    _ = resp.Body.Close() // <--- Add this
    return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论