En Go, tengo algunas respuestas http y a veces me olvido de llamar:
resp.Body.Close()
¿Qué pasa en este caso? habrá una fuga de memoria? ¿También es seguro colocarlo defer resp.Body.Close()
inmediatamente después de obtener el objeto de respuesta?
client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return nil, err
}
¿Qué pasa si hay un error, podía resp
o resp.Body
sea nula?
Respuestas:
Es una fuga de recursos. La conexión no se volverá a utilizar y puede permanecer abierta, en cuyo caso el descriptor de archivo no se liberará.
No, siga el ejemplo proporcionado en la documentación y ciérrelo inmediatamente después de verificar el error.
client := http.DefaultClient resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
De la
http.Client
documentación:fuente
io.LimitReader
. Por lo general, uso un límite bastante pequeño, ya que es más rápido establecer una nueva conexión si la solicitud es demasiado grande._, err := client.Do(req)
también da como resultado que el descriptor de archivo permanezca abierto. Entonces, incluso si a uno no le importa cuál es la respuesta, aún es necesario asignarla a una variable y cerrar el cuerpo.Si
Response.Body
no se cerrará con elClose()
método, los recursos asociados con un fd no se liberarán. Esta es una fuga de recursos.Clausura
Response.Body
De la fuente de respuesta :
Por lo tanto, no hay finalizadores vinculados al objeto y debe cerrarse explícitamente.
Manejo de errores y limpiezas diferidas
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
fuente
Al principio, el descriptor nunca se cierra, como se mencionó anteriormente.
Y lo que es más, golang almacenará en caché la conexión (usando
persistConn
struct para envolver) para reutilizarla, siDisableKeepAlives
es falso.En golang después del
client.Do
método de uso , go ejecutará elreadLoop
método goroutine como uno de los pasos.Entonces, en golang http
transport.go
,pconn(persistConn struct)
no se colocará en elidleConn
canal hasta que se cancele la solicitud en elreadLoop
método, y también esta goroutine (readLoop
método) se bloqueará hasta que se cancele la solicitud.Aquí está el código que lo muestra.
Si quieres saber más, necesitas ver el
readLoop
método.fuente
Consulte https://golang.org/src/net/http/client.go
"Cuando err es nil, resp siempre contiene un resp. No nil".
pero no dicen cuando err! = nil, resp siempre es nil.
Continúan diciendo: "Si resp.Body no está cerrado, es posible que el RoundTripper subyacente del Cliente (normalmente Transporte) no pueda reutilizar una conexión TCP persistente con el servidor para una solicitud subsiguiente de" mantener vivo ".
Entonces, normalmente he resuelto el problema de esta manera:
client := http.DefaultClient resp, err := client.Do(req) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err }
fuente