golang的读取Response.Body时出现了内存泄漏,请大家帮忙一块分析下

读取http.Do返回的Response.Body,时间久了,内存占用在一路上升。

部分代码:

    if response != nil {
        defer response.Body.Close()
    }

read body:

func _ReadResponseBody(r *http.Response) []byte {
    buffer := bytes.NewBuffer(make([]byte, 0, 65536))
    io.Copy(buffer, r.Body)
    temp := buffer.Bytes()
    length := len(temp)
    var body []byte
    if cap(temp) > (length + length/10) {
        body = make([]byte, length)
        copy(body, temp)
    } else {
        body = temp
    }

    return body
}

stackimpact分析
图片描述

参考: http://openmymind.net/Go-Slic...

阅读 14.5k
4 个回答

看代码我感觉你没有理解原文的意思
首先来看你的代码是非常麻烦,申请了大量内存
而原文的意思我猜就是为了避免频繁申请内存才申请了这一大块内存
这句代码应该是一个全局变量
buffer = bytes.NewBuffer(make([]byte, 0, 65536))
然后每次填充数据前先
buffer.Reset()
最后每次http后的数据都填充到这段内存中,从而避免频繁申请内存

你这代码段给的太少了,我猜是不是有一个循环一直一个函数里跑,所以 response.Body.Close() 一直没有被调用。

调用姿势似乎和官方的不一致。

https://golang.org/pkg/net/http/

官方:

resp, err := http.Get("http://example.com/")
if err != nil {
    // handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)

判断err,没有err则defer resp.Body.Close(),不然不关闭。

补充:

  1. 我建议个人不要对官方的包做不同的理解。普通开发按照官方的示例来,除非自己看过源代码。

  2. If the returned error is nil, the Response will contain a non-nil Body which the user is expected to close. If the Body is not closed, the Client's underlying RoundTripper (typically Transport) may not be able to re-use a persistent TCP connection to the server for a subsequent "keep-alive" request.根据官方的说法,err为空则resp.Body不为空,resp.Body为空,则err不为空。所以应该判断resp.Body是否为空,而不是判断resp是否为空。

再补充:

http://devs.cloudimmunity.com...

Most of the time when your http request fails the resp variable will be nil and the err variable will be non-nil. However, when you get a redirection failure both variables will be non-nil. This means you can still end up with a leak.

You can fix this leak by adding a call to close non-nil response bodies in the http response error handling block. Another option is to use one defer call to close response bodies for all failed and successful requests.

存在resp和err都不为空的情况,所以这种情况会造成内存泄露。

defer写在err!=nil里...问题就在这吧

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题