Pertanyaan C # manajemen memori: kata kunci dan pointer yang tidak aman


Apa konsekuensi (positif / negatif) menggunakan tidak aman kata kunci dalam C # menggunakan pointer? Misalnya, apa yang menjadi koleksi sampah, apa keuntungan / kerugian kinerja, apa keuntungan / kerugian kinerja dibandingkan dengan manajemen memori manual bahasa lain, apa bahayanya, di mana situasi itu benar-benar dibenarkan untuk menggunakan bahasa ini fitur, apakah itu lebih lama untuk mengkompilasi ...?


32
2018-03-22 22:30


asal


Jawaban:


Seperti yang telah disebutkan oleh Conrad, ada beberapa situasi di mana akses yang tidak aman ke memori dalam C # berguna. Tidak ada sebanyak dari mereka, tetapi ada beberapa:

  • Memanipulasi dengan Bitmap hampir merupakan contoh umum di mana Anda membutuhkan kinerja tambahan yang bisa Anda dapatkan dengan menggunakan unsafe.

  • Interoperabilitas dengan API yang lebih lama (seperti WinAPI atau native C / C ++ DLL) adalah area lain di mana unsafe bisa sangat berguna - misalnya Anda mungkin ingin memanggil fungsi yang mengambil / mengembalikan pointer unmanaged.

Di sisi lain, Anda dapat menulis sebagian besar hal yang digunakan Marshall kelas, yang menyembunyikan banyak operasi tidak aman di dalam pemanggilan metode. Ini akan menjadi sedikit lebih lambat, tetapi ini adalah pilihan jika Anda ingin menghindari penggunaan unsafe (atau jika Anda menggunakan VB.NET yang tidak memilikinya unsafe)

Konsekuensi positif: Jadi, konsekuensi positif utama dari keberadaan unsafe di C # adalah bahwa Anda dapat menulis beberapa kode lebih mudah (interoperabilitas) dan Anda dapat menulis beberapa kode lebih efisien (memanipulasi dengan bitmap atau mungkin beberapa perhitungan numerik yang berat menggunakan array - meskipun, saya tidak begitu yakin tentang yang kedua).

Konsekuensi negatif: Tentu saja, ada beberapa harga yang harus Anda bayar untuk digunakan unsafe:

  • Kode tidak dapat diverifikasi: C # kode yang ditulis menggunakan unsafe fitur menjadi tidak dapat diverifikasi, yang berarti bahwa kode Anda dapat menyusupi runtime dengan cara apa pun. Ini bukan masalah besar dalam penuh kepercayaan skenario (misalnya aplikasi desktop tidak terbatas) - Anda tidak memiliki semua jaminan .NET CLR yang bagus. Namun, Anda tidak dapat menjalankan aplikasi di lingkungan yang dibatasi seperti hosting web publik, Silverlight, atau kepercayaan sebagian (mis. Aplikasi yang berjalan dari jaringan).

  • Pemulung juga perlu berhati-hati saat Anda menggunakannya unsafe. GC biasanya diizinkan untuk merelokasi objek pada tumpukan yang dikelola (untuk menjaga defragmentasi memori). Saat Anda mengambil penunjuk ke beberapa objek, Anda perlu menggunakan fixed kata kunci untuk memberi tahu GC bahwa ia tidak dapat memindahkan objek sampai Anda selesai (yang mungkin bisa memengaruhi kinerja pengumpulan sampah - tetapi tentu saja, tergantung pada skenario yang tepat).

Tebakan saya bahwa jika C # tidak perlu melakukan interoperasi dengan kode yang lebih lama, itu mungkin tidak akan mendukung unsafe (dan proyek penelitian seperti Singularity yang berusaha menciptakan sistem operasi yang lebih dapat diverifikasi berdasarkan bahasa yang dikelola pasti tidak mengizinkan kita untuk menggunakan kode yang aman). Namun, di dunia nyata, unsafeberguna dalam beberapa kasus (jarang).


26
2018-04-01 18:20



Saya bisa memberi Anda situasi di mana itu layak menggunakan:

Saya harus menghasilkan piksel bitmap dengan pixel. Drawing.Bitmap.SetPixel() terlalu lambat. Jadi saya membangun sendiri dikelola Array data bitmap, dan penggunaan unsafe untuk mendapatkan IntPtr untuk Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr).


8
2018-03-22 23:39



Mengutip Profesional C # 2008:

"Dua alasan utama untuk menggunakan   pointer adalah:

  1. Kompabilitas mundur - Terlepas dari semua fasilitas yang disediakan oleh   .NET-runtime masih bisa dilakukan   memanggil fungsi Windows API asli, dan   untuk beberapa operasi ini mungkin   satu-satunya cara untuk menyertai tugas Anda.   Fungsi-fungsi API ini umumnya   ditulis dalam bahasa C dan sering membutuhkan   pointer sebagai parameter. Namun, di   banyak kasus adalah mungkin untuk menulis   Deklarasi dllImport dengan cara itu   menghindari penggunaan pointer; sebagai contoh,   dengan menggunakan kelas System.IntPtr.
  2. Kinerja - Pada saat-saat di mana kecepatan adalah yang tertinggi   Pentingnya, pointer dapat memberikan   rute ke kinerja yang dioptimalkan. Jika kamu   tahu apa yang Anda lakukan, Anda bisa   memastikan bahwa data diakses atau   dimanipulasi dengan cara yang paling efisien.   Namun, sadari itu, lebih sering   daripada tidak, ada area lain dari   kode Anda di mana Anda dapat membuat yang diperlukan   meningkatkan kinerja tanpa   reselling ke pointer. Coba gunakan a   profiler kode untuk mencari kemacetan   dalam kode Anda - satu dilengkapi dengan Visual   Studio 2008. "

Dan jika Anda menggunakan penunjuk, kode Anda akan memerlukan tuas kepercayaan yang lebih tinggi untuk dieksekusi dan jika pengguna tidak mengabulkan bahwa kode Anda tidak akan berjalan.

Dan membungkusnya dengan kutipan terakhir:

"Kami sangat menyarankan untuk tidak menggunakannya   pointer tidak perlu karena itu akan   tidak hanya lebih sulit untuk menulis dan men-debug,   tetapi itu juga akan gagal memori   pemeriksaan keamanan jenis yang diberlakukan oleh   CLR. "


4
2018-03-22 22:49



Pengumpulan sampah tidak efisien dengan benda-benda berumur panjang. .Net's garbage collector bekerja paling baik ketika kebanyakan objek dilepaskan dengan cepat, dan beberapa objek "hidup selamanya." Masalahnya adalah benda yang berumur lebih panjang hanya dilepaskan selama pengumpulan sampah penuh, yang menimbulkan penalti kinerja yang signifikan. Intinya, benda-benda berumur panjang dengan cepat pindah ke generasi 2.

(Untuk informasi lebih lanjut, Anda mungkin ingin membaca tentang. Kolektor sampah generasi Netral: http://msdn.microsoft.com/en-us/library/ms973837.aspx)

Dalam situasi di mana objek, atau penggunaan memori secara umum, akan berumur panjang, manajemen memori manual akan menghasilkan kinerja yang lebih baik karena dapat dilepaskan ke sistem tanpa memerlukan pengumpulan sampah penuh.

Menerapkan beberapa jenis sistem manajemen memori berbasis di sekitar array byte besar tunggal, struct, dan banyak aritmatika pointer, secara teoritis dapat meningkatkan kinerja dalam situasi di mana data akan disimpan dalam RAM untuk waktu yang lama.

Sayangnya, saya tidak mengetahui cara yang baik untuk melakukan manajemen memori manual. Bersih untuk objek yang akan berumur panjang. Ini pada dasarnya berarti bahwa aplikasi yang memiliki data lama di RAM secara berkala akan menjadi tidak responsif ketika mereka menjalankan pengumpulan sampah penuh dari semua memori.


1
2017-08-16 08:43