Pertanyaan Mengapa menggunakan FinalReleaseComObject, bukan ReleaseComObject?


Saya tahu perbedaan dasar sebagai ReleaseComObject hanya mengurangi beberapa counter oleh satu dan FinalReleaseComObject menurunkannya menjadi nol.

Jadi yang biasanya saya dengar adalah panggilan FinalReleaseComObject karena dengan demikian Anda yakin bahwa objek COM benar-benar dilepaskan.

Tapi ini membuatku bertanya-tanya, ada gunanya counter ini kan? Apakah Anda tidak melanggar mekanisme itu jika Anda selalu menelepon FinalReleaseComObject. Jika counter itu tidak satu sebelum kamu menelepon ReleaseComObject, apakah tidak ada alasan untuk itu?

Apa yang bisa menyebabkannya lebih tinggi dari satu padahal seharusnya tidak?

Terima kasih sebelumnya.

PS: Pengalaman COM saya hanya terdiri dari menggunakan Excel Interop. Tidak yakin apakah pertanyaan ini lokal ke domain itu (misalnya di luar Kantor Interop, FinalReleaseComObject tidak sering digunakan).

Perbarui 1

Itu artikel Dan pembicaraan yang disebutkan tentang penggunaan ReleaseComObject setelah selesai. Seperti yang saya mengerti dari artikel, ini adalah cara normal. Saya pikir jika Anda melakukan ini secara konsisten, itu akan berfungsi dengan baik. Dalam komentar ke artikel penulis menyarankan seseorang untuk menelepon ReleaseComObject dalam satu lingkaran sampai benar-benar dilepaskan ( artikel dari tahun 2006, jadi ini analog untuk menelepon FinalReleaseComObject). Namun dia juga menyatakan bahwa ini bisa berbahaya.

Jika Anda benar-benar ingin RCW untuk memanggil Release () pada titik tertentu dalam kode, Anda dapat memanggil ReleaseComObject () dalam satu lingkaran sampai nilai kembalinya mencapai nol. Ini harus memastikan RCW akan memanggil Release (). Namun, jika Anda melakukan itu, berhati-hatilah, ketika referensi terkelola lainnya mencoba menggunakan RCW itu, itu akan menyebabkan pengecualian. "

Ini membuat saya percaya bahwa itu memang benar tidak ide bagus untuk selalu menelepon FinalReleaseComObject, karena Anda dapat menyebabkan pengecualian di tempat lain. Seperti yang saya lihat sekarang, Anda hanya harus memanggil ini jika Anda benar-benar yakin bahwa Anda bisa.

Namun, saya memiliki sedikit pengalaman dalam hal ini. Saya tidak tahu bagaimana saya bisa yakin. Jika penghitung meningkat ketika seharusnya tidak, apakah tidak lebih baik untuk memperbaiki masalah itu? Jika demikian, maka saya akan mengatakan FinalReleaseComObject lebih merupakan peretasan daripada praktik terbaik.


32
2017-12-01 15:50


asal


Jawaban:


Beberapa basa-basi ...

A Runtime Callable Wrapper (RCW) hanya memanggil IUnknown.AddRef sekali pada antarmuka COM yang tidak dikelola yang dibungkusnya. Namun, RCW juga mempertahankan hitungan terpisah dari jumlah referensi yang dikelola di sana untuk RCW itu sendiri. Ini adalah jumlah terpisah dari referensi yang dikelola yang dikurangi dengan panggilan ke Marshal.ReleaseComObject. Ketika hitungan referensi yang dikelola mencapai nol, RCW memanggil IUnknown. Rilis sekali pada antarmuka COM yang tidak dikelola.

Marshal.FinalReleaseComObject mengambil jumlah referensi yang dikelola ke nol dengan satu panggilan, dan dengan demikian memanggil metode IUnknown.Release unmanaged dibungkus segera (dengan asumsi bahwa jumlah referensi yang dikelola belum nol).

Jadi mengapa memiliki kedua Marshal.ReleaseComObject dan Marshal.FinalReleaseComObject? Memanggil Marshal.FinalReleaseComObject hanya menghindari harus menulis loop yang memanggil Marshal.ReleaseComObject berulang kali sampai mengembalikan 0 ketika Anda ingin menunjukkan bahwa Anda telah sangat selesai menggunakan objek COM sekarang.

Mengapa menggunakan Marshal.ReleaseComObject atau Marshal.FinalReleaseComObject? Ada dua alasan yang saya ketahui:

Yang pertama adalah untuk memastikan bahwa sumber daya yang tidak dikelola (seperti menangani file, memori dll) yang digunakan oleh objek COM yang dibungkus dibebaskan sesegera mungkin sebagai akibat dari panggilan yang dihasilkan ke metode IUnknown.Release () unmanaged.

Yang kedua adalah memastikan bahwa thread yang memanggil metode IUnknown.Release () yang tidak dikelola berada di bawah kendali Anda, dan bukan thread finalizer.

Tanpa panggilan ke salah satu metode Marshal ini, finalisasi RCW akan akhirnya panggil metode IUnknown.Release () yang tidak dikelola beberapa saat setelah RCW mengumpulkan sampah.

Untuk detail yang menguatkan, lihat entri blog Visual C ++ Team Mencampur pembersihan deterministik dan non-deterministik 


35
2017-12-01 18:00