如果我不闭合反应会发生什么,尸体?

在 Go 中,我有一些 http 回复,有时我会忘记打电话:

resp.Body.Close()

这种情况下会发生什么?会有内存泄漏吗?在得到响应对象之后立即放入 defer resp.Body.Close()是否安全?

client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return nil, err
}

如果出现错误,respresp.Body是否为零?

81645 次浏览

这种情况下会发生什么? 会有内存泄漏吗?

是资源泄露。连接将不会被重用,并且可以保持打开状态,在这种情况下文件描述符将不会被释放。

另外,在获得响应对象之后立即放入 Deferresp.Body. Close ()是否安全?

不,按照文档中提供的示例进行操作,并在检查错误后立即关闭它。

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

来自 http.Client文档:

如果返回的错误为 nil,则 Response 将包含一个用户希望关闭的非 nil Body。如果 Body 没有被读取到 EOF 并关闭,那么客户机的底层 RoundTripper (通常是 Transport)可能无法重用到服务器的持久 TCP 连接以满足后续的“ keep-alive”请求。

参见 https://golang.org/src/net/http/client.go
当 err 为零时,rep 总是包含非零 rep. Body

但他们没有说什么时候 err! = nil,rep 总是0。他们接着说:
”如果。主体没有关闭,客户机的底层 RoundTripper (通常是 Transport)可能无法重用到服务器的持久 TCP 连接,以满足后续的“ keep-alive”请求

所以我通常是这样解决问题的:

client := http.DefaultClient
resp, err := client.Do(req)
if resp != nil {
defer resp.Body.Close()
}
if err != nil {
return nil, err
}

如果 Response.Body不能用 Close()方法关闭,那么与 fd 相关联的资源就不会被释放。这是资源泄露。

关闭 Response.Body

来自 响应源:

关闭 Body 是呼叫者的责任。

所以没有绑定到对象的终结器,必须显式地关闭它。

错误处理和延迟清理

在出错时,任何响应都可以忽略。只有当 CheckRedirect 失败时,才会发生带有非 nil 错误的非 nil 响应,即使在此时,也会发生返回的 Response。尸体已经闭合了。

resp, err := http.Get("http://example.com/")
if err != nil {
// Handle error if error is non-nil
}
defer resp.Body.Close() // Close body only if response non-nil

起初,描述符永远不会关闭,正如上面提到的那样。

而且,如果 DisableKeepAlives为 false,golang 将缓存连接(使用 persistConn struct 来包装)以便重用它。

在戈朗使用 client.Do方法后,去将运行 goroutine readLoop方法作为其中的一个步骤。

因此,在 golang http transport.go中,除非 readLoop方法中的请求被取消,否则 pconn(persistConn struct)不会被放入 idleConn通道,而这个 goroutine (readLoop方法)将被阻塞,直到请求被取消。

下面是显示它的代码

如果您想了解更多信息,您需要查看 readLoop方法。

一种选择是将最后的请求放入一个新的上下文中,这样您就可以 如果需要,可以使用相同的变量名,而不必担心会重复使用任何变量名 现有的变量,并仍然关闭一切:

package main


import (
"bytes"
"net/http"
)


func main() {
b := new(bytes.Buffer)
// request one
r, e := http.Get("http://speedtest.atl.hivelocity.net")
if e != nil {
panic(e)
}
defer r.Body.Close()
b.ReadFrom(r.Body)
// request two
{
r, e := http.Get("http://speedtest.lax.hivelocity.net")
if e != nil {
panic(e)
}
defer r.Body.Close()
b.ReadFrom(r.Body)
}
// print
print(b.String())
}