如果我不做出反应,会发生什么。在golang身上?

时间:2015-10-20 13:49:41

标签: go

在golang中我有一些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可能为零?

5 个答案:

答案 0 :(得分:63)

  

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

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

  

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

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

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

来自http.Client文档:

  

如果返回的错误为nil,则Response将包含一个非零的Body,用户应该关闭它。如果Body未被读取到EOF并且已关闭,则客户端的基础RoundTripper(通常为Transport)可能无法重新使用到服务器的持久TCP连接以用于后续" keep-alive&# 34;请求。

答案 1 :(得分:8)

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

结束Response.Body

来自response source

  

呼叫者有责任关闭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

答案 2 :(得分:1)

https://golang.org/src/net/http/client.go
“当err为nil时,resp总是包含一个非零的resp.Body。”

但他们没有说错误!= nil,resp总是为零。他们继续说:
“如果resp.Body未关闭,则客户端的基础RoundTripper(通常为Transport)可能无法重新使用到服务器的持久TCP连接,以用于后续的”保持活动“请求。”

所以我通常解决了这个问题:

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

答案 3 :(得分:1)

首先,描述符永远不会关闭,如上所述。

而且,如果persistConn为假,golang将缓存连接(使用DisableKeepAlives struct to wrap)以重用它。

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

因此,在golang http transport.go中,pconn(persistConn struct)将不会被放入idleConn频道,直到readLoop方法中的请求被取消,而且此goroutine({ {1}}方法)将被阻止,直到请求被取消。

Here is the code显示它。

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

答案 4 :(得分:0)

一种选择是将子请求请求放入新的上下文中,这样您就可以 如果需要,可以使用相同的变量名,而不必担心破坏任何 现有变量,仍然关闭所有内容:

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())
}