No Go, tenho algumas respostas http e às vezes me esqueço de ligar para:
resp.Body.Close()
O que acontece nesse caso? haverá um vazamento de memória? Também é seguro colocar defer resp.Body.Close()
imediatamente após obter o objeto de resposta?
client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return nil, err
}
E se houver um erro, pode resp
ou resp.Body
ser nulo?
Respostas:
É um vazamento de recursos. A conexão não será reutilizada e pode permanecer aberta, caso em que o descritor de arquivo não será liberado.
Não, siga o exemplo fornecido na documentação e feche-o imediatamente após verificar o erro.
client := http.DefaultClient resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
Da
http.Client
documentação:fonte
io.LimitReader
. Eu normalmente uso um limite bem pequeno, já que é mais rápido fazer uma nova conexão se a solicitação for muito grande._, err := client.Do(req)
também faz com que o descritor de arquivo permaneça aberto. Assim, mesmo que não se importe qual é a resposta, ainda é necessário atribuí-la a uma variável e fechar o corpo.Se
Response.Body
não for fechado comClose()
método, os recursos associados a um fd não serão liberados. Este é um vazamento de recursos.Fechando
Response.Body
Da fonte de resposta :
Portanto, não há finalizadores vinculados ao objeto e ele deve ser fechado explicitamente.
Tratamento de erros e limpezas adiadas
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
fonte
A princípio o descritor nunca fecha, como as coisas mencionadas acima.
E o que é mais, golang irá armazenar em cache a conexão (usando
persistConn
struct para embrulhar) para reutilizá-la, seDisableKeepAlives
for false.No golang após o
client.Do
método de uso , go irá executar o goroutinereadLoop
método como uma das etapas.Portanto, em golang http
transport.go
, apconn(persistConn struct)
não será colocado noidleConn
canal até que o req seja cancelado noreadLoop
método, e também esta goroutine (readLoop
método) será bloqueada até que o req seja cancelado.Aqui está o código que o mostra.
Se você quiser saber mais, você precisa ver o
readLoop
método.fonte
Veja https://golang.org/src/net/http/client.go
"Quando err é nulo, resp sempre contém um resp.Body não nulo."
mas eles não dizem quando err! = nulo, resp sempre é nulo. Eles continuam a dizer:
"Se resp.Body não estiver fechado, o RoundTripper subjacente do Cliente (normalmente Transporte) pode não ser capaz de reutilizar uma conexão TCP persistente com o servidor para uma solicitação" keep-alive "subsequente."
Então, normalmente resolvo o problema assim:
client := http.DefaultClient resp, err := client.Do(req) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err }
fonte