我正在使用以下功能下载小于20MB的文件。它将整个内容读入内存,因为另一个函数必须先对字节进行处理才能将其写入磁盘。
func getURL(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("getURL: %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("getURL: %s", err)
}
return body, nil
}
这样可以正常工作,但系统会消耗所有内存。
是否有可能释放body
在被另一个函数处理后使用的内存,因此内存使用量不会大于当前正在处理的字节数?
答案 0 :(得分:8)
首先,我建议您阅读以下问题/答案:
Golang - Cannot free memory once occupied by bytes.Buffer
您可以触发gc以runtime.GC()
释放未使用的对象,并且您可以敦促Go运行时使用debug.FreeOSMemory()
将内存释放回操作系统,但所有这些只是消防。一个写得很好的Go应用程序永远不必调用它们。
您应该做的是阻止运行时分配大量内存。
你怎么能实现这个目标?一些方法(你甚至可以结合这些解决方案):
限制服务需要大量内存的请求,更多信息:Process Management for the Go Webserver;还Is this an idiomatic worker thread pool in Go?
使用内存/缓冲池,不要一直分配大数组/切片,更多关于它:How to implement Memory Pooling in Golang
创建/更改您的处理单元不要在字节片上操作,而是在io.Reader
上操作,因此您不需要将所有内容读入内存,您只需通过{{1} } 上。请注意,即使多个单元必须读取/检查主体,仍然可以只读取和处理一次,而不是将其保留在内存中。手段可以是io.Pipe()
,io.TeeReader()
或自定义解决方案。