如果我不关闭响应会发生什么.在golang身上?

Dan*_*son 66 go

在Golang我有一些http响应,我有时忘记打电话:

resp.Body.Close()
Run Code Online (Sandbox Code Playgroud)

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

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

如果有错误怎么办,可能resp或者resp.Body是零?

Jim*_*imB 77

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

这是资源泄漏.连接可以保持打开状态,在这种情况下,不会释放文件描述符.

获取响应对象后立即放入resp.Body.Close()也是安全的吗?

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

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

http.Client文档:

出错时,可以忽略任何响应.只有在CheckRedirect失败时才会出现带有非零错误的非零响应,即使这样,返回的Response.Body也已关闭.

  • @mmcdole:那个帖子是错的,并且不能保证不会出现恐慌,因为错误返回的任何响应都没有定义的状态.如果Body没有因错误而关闭,那么这是一个bug,需要报告.您应该通过[官方客户端文档](https://golang.org/pkg/net/http/#Client.Do),其中指出"出错时,可以忽略任何响应",而不是随机博客文章. (8认同)
  • 值得指出的是,执行 `_, err := client.Do(req)` 也会导致文件描述符保持打开状态。因此,即使不关心响应是什么,仍然有必要将其分配给一个变量并关闭主体。 (4认同)
  • 根据此[link](http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#close_http_resp_body),仍然可能泄漏与您的代码的连接.在某些情况下,响应为非零且错误为非零. (2认同)
  • @ del-boy:如果您希望客户端发出更多请求,那么您应该尝试读取正文,以便可以重用连接.如果您不需要连接,那么不要费心阅读身体.如果您阅读正文,请使用`io.LimitReader`进行包装.我通常使用一个相当小的限制,因为如果请求太大,建立新连接会更快. (2认同)
  • 对于任何感兴趣的人,完整的文档是(强调):“发生错误时,任何响应都可以被忽略。只有当 CheckRedirect 失败时才会出现具有非零错误的非零响应,并且_即使那么_返回的 Response.Body 已经是关闭。” (2认同)

I15*_*159 9

如果Response.Body不使用Close()方法关闭,则不会释放与fd关联的资源.这是资源泄漏.

闭幕 Response.Body

来自回复来源:

关闭Body是调用者的责任.

因此没有绑定到对象的终结器,必须明确关闭它.

错误处理和延迟清理

出错时,可以忽略任何响应.只有在CheckRedirect失败时才会出现带有非零错误的非零响应,即使这样,返回的Response.Body也已关闭.

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
Run Code Online (Sandbox Code Playgroud)

  • 您应该注意它们应该在您的错误处理条件内返回。如果用户在错误处理中没有返回,这将导致恐慌。 (4认同)

小智 6

起初,描述符永远不会关闭,如上所述。

更重要的是,golang 将缓存连接(使用persistConnstruct 来包装)以重用它,如果DisableKeepAlives为 false。

在 golang 中使用client.Do方法之后,go 将运行 goroutinereadLoop方法作为步骤之一。

所以在 golang http 中transport.go,apconn(persistConn struct)不会被放入idleConn通道,直到 req 在readLoop方法中取消,并且这个 goroutine( readLoopmethod) 将被阻塞,直到 req 取消。

这是显示它的代码

如果你想了解更多,你需要看看readLoop方法。