内存管理 – 多部分表单上传golang中的内存泄漏?

内存管理 – 多部分表单上传golang中的内存泄漏?,第1张

概述以下服务器代码: package mainimport ( "fmt" "net/http")func handler(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile("file") if err != nil { fmt.Fprintln(w, err) retur 以下服务器代码:

package mainimport (  "fmt"  "net/http")func handler(w http.ResponseWriter,r *http.Request) {  file,_,err := r.Formfile("file")  if err != nil {    fmt.Fprintln(w,err)    return  }  defer file.Close()  return}func main() {  http.ListenAndServe(":8081",http.HandlerFunc(handler))}

正在运行然后调用它:

curl -i -F "file=@./large-file" --form hello=world http://localhost:8081/

大文件大约80MB的地方似乎在darwin / amd64和linux / amd64的Go 1.4.2中有某种形式的内存泄漏.

当我连接pprof时,我看到bytes.makeSlice在调用服务几次后使用了96MB内存(最终在上面的代码中由r.Formfile调用).

如果我继续调用curl,那么进程的内存使用量会随着时间的推移而变慢,最终看起来在我的机器上大约300MB.

思考?我认为这不是预料/我做错了什么?

解决方法 如果内存使用停滞在“最大”,我不会真的称之为内存泄漏.我宁愿说GC不急切而且懒惰.或者只是不经常重新分配/需要物理释放内存.如果它确实是内存泄漏,则使用的内存不会停止在300 MB.

r.Formfile(“file”)将导致调用Request.ParseMultipartForm(),并将32 MB用作maxMemory参数的值(request.go中定义的defaultMaxMemory变量的值).由于您上传了一个较大的文件(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文件时这样做,您可能不会遇到这种情况.

如果它对您很重要,您也可以使用较小的maxMemory值手动调用Request.ParseMultipartForm(),例如

r.ParseMultipartForm(2 << 20) // 2 MBfile,err := r.Formfile("file")// ... rest of your handler

在后台分配更少(和更少)的缓冲区.

总结

以上是内存溢出为你收集整理的内存管理 – 多部分表单上传golang中的内存泄漏?全部内容,希望文章能够帮你解决内存管理 – 多部分表单上传golang中的内存泄漏?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1044665.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-24
下一篇2022-05-24

发表评论

登录后才能评论

评论列表(0条)

    保存