1 回答
TA贡献1906条经验 获得超3个赞
如果内存使用量停滞在“最大值”,我不会真正称其为内存泄漏。我宁愿说 GC 不急切和懒惰。或者只是不想物理释放内存,如果它经常被重新分配/需要。如果真的是内存泄漏,使用的内存不会停留在 300 MB。
r.FormFile("file")将导致调用Request.ParseMultipartForm(),并且 32 MB 将用作maxMemory参数的值(在 中defaultMaxMemory定义的变量的值request.go)。由于您上传了一个更大的文件 (80 MB),因此至少会创建一个大小为 32 MB 的缓冲区 - 最终(这在 中实现multipart.Reader.ReadFrom())。由于bytes.Buffer用于读取内容,读取过程将从一个小的或空的缓冲区开始,并在需要更大的缓冲区时重新分配。
缓冲区重新分配的策略和缓冲区大小取决于实现(并且还取决于从请求中读取/解码的块的大小),但只是为了有一个粗略的图片,想象一下:0 字节,4 KB, 16 KB、64 KB、256 KB、1 MB、4 MB、16 MB、64 MB。同样,这只是理论上的,但说明总和甚至可以增长超过 100 MB,只是为了读取内存中文件的前 32 MB,此时将决定将其移动/存储在文件中。有关multipart.Reader.ReadFrom()详细信息,请参阅 的实现。这合理地解释了 96 MB 的分配。
这样做几次,如果 GC 不立即释放分配的缓冲区,您很容易得到 300 MB。并且如果有足够的空闲内存,GC 就没有压力急于释放内存。你看到它增长相对较大的原因是因为在后台使用了大缓冲区。您是否会在上传 1MB 文件时做同样的事情,您可能不会遇到这种情况。
如果它对您很重要,您也可以Request.ParseMultipartForm()手动调用较小的maxMemory值,例如
r.ParseMultipartForm(2 << 20) // 2 MB
file, _, err := r.FormFile("file")
// ... rest of your handler
在后台分配更小(和更少)的缓冲区。
- 1 回答
- 0 关注
- 341 浏览
添加回答
举报