无法释放内存字节缓冲区。

huangapple go评论115阅读模式
英文:

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(&quot;https://api.datadoghq.com/api/v1/series?api_key=&quot;+env.GetDataDogKey(), &quot;application/json&quot;, bytes.NewBuffer(b))
    if err != nil {
        logger.Error(ctx, &quot;Error submitting event to datadog, err = &quot;, err)
        return err
    }
    logger.Info(ctx, resp)
    _ = resp.Body.Close() // &lt;--- Add this
    return nil
}

huangapple
  • 本文由 发表于 2023年2月17日 16:48:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75482023.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定