Di Go, saya mendapat beberapa tanggapan http dan terkadang saya lupa menelepon:
resp.Body.Close()
Apa yang terjadi dalam kasus ini? apakah akan ada kebocoran memori? Juga apakah aman untuk dimasukkan defer resp.Body.Close()
segera setelah mendapatkan objek respon?
client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return nil, err
}
Bagaimana jika ada kesalahan, bisa resp
atau resp.Body
nihil?
Jawaban:
Ini kebocoran sumber daya. Sambungan tidak akan digunakan kembali, dan dapat tetap terbuka dalam hal ini deskriptor file tidak akan dibebaskan.
Tidak, ikuti contoh yang diberikan dalam dokumentasi dan tutup segera setelah memeriksa kesalahan.
client := http.DefaultClient resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close()
Dari
http.Client
dokumentasi:sumber
io.LimitReader
. Saya biasanya menggunakan batas yang cukup kecil, karena lebih cepat membuat sambungan baru jika permintaan terlalu besar._, err := client.Do(req)
juga akan membuat deskriptor file tetap terbuka. Jadi bahkan jika seseorang tidak peduli apa responnya, tetap perlu untuk menugaskannya ke variabel dan menutup tubuh.Jika
Response.Body
tidak akan ditutup denganClose()
metode daripada sumber daya yang terkait dengan fd tidak akan dibebaskan. Ini adalah kebocoran sumber daya.Penutupan
Response.Body
Dari sumber tanggapan :
Jadi tidak ada finalisator yang terikat ke objek dan harus ditutup secara eksplisit.
Penanganan kesalahan dan pembersihan tertunda
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
sumber
Awalnya deskriptor tidak pernah menutup, seperti hal-hal yang disebutkan di atas.
Dan terlebih lagi, golang akan meng-cache koneksi (menggunakan
persistConn
struct untuk membungkus) untuk digunakan kembali, jikaDisableKeepAlives
salah.Pada golang after use
client.Do
method, go akan menjalankanreadLoop
metode goroutine sebagai salah satu langkahnya.Jadi pada golang http
transport.go
, apconn(persistConn struct)
tidak akan dimasukkan keidleConn
channel sampai req dibatalkan dalamreadLoop
metode tersebut, dan juga goroutine (readLoop
metode) ini akan diblokir sampai req tersebut dibatalkan.Ini kode yang menunjukkannya.
Jika Anda ingin tahu lebih banyak, Anda perlu melihat
readLoop
caranya.sumber
Lihat https://golang.org/src/net/http/client.go
"Jika err nihil, resp selalu berisi resp.Body non-nil."
tetapi mereka tidak mengatakan bila err! = nil, resp selalu nihil. Mereka melanjutkan dengan mengatakan:
"Jika resp.Body tidak ditutup, RoundTripper yang mendasari Klien (biasanya Transport) mungkin tidak dapat menggunakan kembali koneksi TCP persisten ke server untuk permintaan" tetap hidup "berikutnya."
Jadi saya biasanya memecahkan masalah seperti ini:
client := http.DefaultClient resp, err := client.Do(req) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err }
sumber