Saya memiliki kode berikut:
MemoryStream foo(){
MemoryStream ms = new MemoryStream();
// write stuff to ms
return ms;
}
void bar(){
MemoryStream ms2 = foo();
// do stuff with ms2
return;
}
Apakah ada kemungkinan MemoryStream yang telah saya alokasikan akan gagal dibuang nanti?
Saya mendapat tinjauan sejawat yang memaksa saya menutup ini secara manual, dan saya tidak dapat menemukan informasi untuk mengetahui apakah dia benar atau tidak.
c#
.net
memory-leaks
memorystream
Pembuat kode
sumber
sumber
Jawaban:
Jika ada sesuatu yang Dapat Disposable, Anda harus selalu Buang. Anda harus menggunakan
using
pernyataan dalambar()
metode Anda untuk memastikanms2
dibuang.Ini pada akhirnya akan dibersihkan oleh pengumpul sampah, tetapi panggilan Buang selalu merupakan praktik yang baik. Jika Anda menjalankan FxCop pada kode Anda, itu akan menandainya sebagai peringatan.
sumber
Anda tidak akan membocorkan apa pun - setidaknya dalam implementasi saat ini.
Memanggil Dispose tidak akan membersihkan memori yang digunakan oleh MemoryStream lebih cepat. Ini akan menghentikan streaming Anda agar tidak layak untuk panggilan Baca / Tulis setelah panggilan, yang mungkin berguna atau mungkin tidak berguna bagi Anda.
Jika Anda benar-benar yakin tidak ingin berpindah dari MemoryStream ke jenis aliran lain, tidak ada salahnya jika Anda tidak memanggil Buang. Namun, itu praktek yang umumnya baik sebagian karena jika Anda pernah melakukan perubahan untuk menggunakan Stream yang berbeda, Anda tidak ingin mendapatkan digigit oleh bug sulit menemukan karena Anda memilih jalan keluar yang mudah awal. (Di sisi lain, ada argumen YAGNI ...)
Alasan lain untuk tetap melakukannya adalah bahwa implementasi baru dapat memperkenalkan sumber daya yang akan dibebaskan di Buang.
sumber
IDisposable
adalah kasus khusus yang bertentangan dengan praktik terbaik normal, Anda dapat berargumen bahwa kasus tersebut tidak boleh Anda lakukan sampai Anda benar-benar membutuhkannya, di bawah YAGNI prinsip.Ya ada sebuah kebocoran , tergantung pada bagaimana Anda mendefinisikan LEAK dan berapa banyak KEMUDIAN Anda maksud ...
Jika yang Anda maksud dengan kebocoran adalah "memori tetap dialokasikan, tidak tersedia untuk digunakan, meskipun Anda sudah selesai menggunakannya" dan yang terakhir Anda maksudkan kapan saja setelah memanggil buang, maka ya mungkin ada kebocoran, meskipun tidak permanen (mis. Untuk umur runtime aplikasi Anda).
Untuk membebaskan memori terkelola yang digunakan oleh MemoryStream, Anda perlu membatalkan referensi, dengan membatalkan referensi ke sana, sehingga memori tersebut memenuhi syarat untuk pengumpulan sampah segera. Jika Anda gagal melakukan ini, maka Anda membuat kebocoran sementara sejak Anda selesai menggunakannya, sampai referensi Anda keluar dari ruang lingkup, karena sementara itu memori tidak akan tersedia untuk alokasi.
Manfaat dari pernyataan using (lebih dari sekedar memanggil buang) adalah bahwa Anda dapat MENYATAKAN referensi Anda dalam pernyataan using. Ketika pernyataan using selesai, tidak hanya dispose dipanggil, tetapi referensi Anda keluar dari ruang lingkup, secara efektif meniadakan referensi dan membuat objek Anda memenuhi syarat untuk pengumpulan sampah segera tanpa mengharuskan Anda untuk mengingat untuk menulis kode "reference = null".
Meskipun tidak langsung membatalkan referensi bukanlah kebocoran memori "permanen" klasik, hal itu pasti memiliki efek yang sama. Misalnya, jika Anda menyimpan referensi ke MemoryStream (bahkan setelah memanggil buang), dan sedikit lebih jauh dalam metode Anda, Anda mencoba mengalokasikan lebih banyak memori ... memori yang digunakan oleh aliran memori yang masih direferensikan tidak akan tersedia kepada Anda sampai Anda membatalkan referensi atau keluar dari ruang lingkup, meskipun Anda menelepon buang dan selesai menggunakannya.
sumber
Menelepon
.Dispose()
(atau membungkus denganUsing
) tidak diperlukan.Alasan Anda menelepon
.Dispose()
adalah untuk merilis sumber daya secepat mungkin .Pikirkan dalam hal, katakanlah, server Stack Overflow, di mana kami memiliki sekumpulan memori terbatas dan ribuan permintaan masuk. Kami tidak ingin menunggu pengumpulan sampah terjadwal, kami ingin melepaskan memori itu secepatnya sehingga tersedia untuk permintaan baru yang masuk.
sumber
FileStream
objek dan gaya yang berbeda untukMemoryStream
objek?Ini sudah dijawab, tetapi saya hanya akan menambahkan bahwa prinsip menyembunyikan informasi kuno yang baik berarti Anda mungkin pada suatu saat ingin melakukan refactor:
untuk:
Ini menekankan bahwa penelepon tidak boleh peduli jenis Stream apa yang dikembalikan, dan memungkinkan untuk mengubah implementasi internal (misalnya, saat mengejek pengujian unit).
Anda kemudian akan mendapat masalah jika Anda belum pernah menggunakan Buang dalam penerapan bilah Anda:
sumber
Semua aliran menerapkan IDisposable. Bungkus aliran Memori Anda dalam pernyataan penggunaan dan Anda akan baik-baik saja dan keren. Blok penggunaan akan memastikan aliran Anda ditutup dan dibuang apa pun yang terjadi.
di mana pun Anda memanggil Foo, Anda dapat melakukannya menggunakan (MemoryStream ms = foo ()) dan saya pikir Anda masih harus baik-baik saja.
sumber
Anda tidak akan membocorkan memori, tetapi peninjau kode Anda benar untuk menunjukkan bahwa Anda harus menutup aliran Anda. Itu sopan untuk dilakukan.
Satu-satunya situasi di mana Anda mungkin membocorkan memori adalah ketika Anda secara tidak sengaja meninggalkan referensi ke aliran dan tidak pernah menutupnya. Anda masih tidak benar-benar membocorkan memori, tetapi Anda tidak perlu memperpanjang waktu yang Anda klaim untuk menggunakannya.
sumber
Saya akan merekomendasikan membungkus MemoryStream
bar()
dalam sebuahusing
pernyataan terutama untuk konsistensi:.Dispose()
, tetapi ada kemungkinan bahwa di beberapa titik di masa mendatang mungkin, atau Anda (atau orang lain di perusahaan Anda) mungkin menggantinya dengan MemoryStream kustom Anda sendiri yang melakukannya, dll.Hal lain yang biasanya saya lakukan dalam kasus-kasus seperti
foo()
saat membuat dan mengembalikan IDisposable adalah memastikan bahwa setiap kegagalan antara membangun objek danreturn
ditangkap oleh pengecualian, membuang objek, dan meluncurkan kembali pengecualian:sumber
Jika sebuah objek mengimplementasikan IDisposable, Anda harus memanggil metode .Dispose setelah selesai.
Di beberapa objek, Buang artinya sama dengan Tutup dan sebaliknya, dalam hal ini, baik.
Sekarang, untuk pertanyaan khusus Anda, tidak, Anda tidak akan membocorkan memori.
sumber
Saya bukan ahli .net, tapi mungkin masalahnya di sini adalah sumber daya, yaitu pegangan file, dan bukan memori. Saya kira pengumpul sampah pada akhirnya akan membebaskan aliran, dan menutup pegangan, tetapi saya pikir akan selalu menjadi praktik terbaik untuk menutupnya secara eksplisit, untuk memastikan Anda membuang konten ke disk.
sumber
Pembuangan sumber daya yang tidak dikelola bersifat non-deterministik dalam bahasa pengumpulan sampah. Bahkan jika Anda memanggil Buang secara eksplisit, Anda sama sekali tidak memiliki kendali atas kapan memori pendukung benar-benar dibebaskan. Buang secara implisit dipanggil saat sebuah objek keluar dari ruang lingkup, apakah itu dengan keluar dari pernyataan using, atau memunculkan callstack dari metode subordinat. Ini semua dikatakan, kadang-kadang objek sebenarnya bisa menjadi pembungkus untuk sumber daya yang dikelola (misalnya file). Inilah mengapa praktik yang baik untuk menutup secara eksplisit di pernyataan akhirnya atau menggunakan pernyataan using. Bersulang
sumber
MemorySteram tidak lain adalah array byte, yang merupakan obyek yang dikelola. Lupa untuk membuang atau menutup ini tidak memiliki efek samping selain di atas kepala penyelesaian.
Cukup periksa metode penyusun atau siram MemoryStream di reflektor dan akan jelas mengapa Anda tidak perlu khawatir tentang menutup atau membuangnya selain hanya untuk mengikuti praktik yang baik.
sumber