
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中的内存泄漏?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)