Adakah yang pernah benar-benar digunakan stackalloc
saat memprogram di C #? Saya mengetahui apa itu fungsinya, tetapi satu-satunya saat itu muncul di kode saya adalah secara tidak sengaja, karena Intellisense menyarankannya ketika saya mulai mengetik static
, misalnya.
Meskipun tidak terkait dengan skenario penggunaan stackalloc
, saya sebenarnya melakukan interop lama dalam jumlah besar di aplikasi saya, jadi sesekali saya dapat menggunakan unsafe
kode. Tapi bagaimanapun saya biasanya menemukan cara untuk menghindari unsafe
sepenuhnya.
Dan karena ukuran tumpukan untuk satu utas di .Net adalah ~ 1Mb (perbaiki saya jika saya salah), saya bahkan lebih dilindungi dari penggunaan stackalloc
.
Adakah beberapa kasus praktis di mana seseorang dapat berkata: "ini adalah jumlah data dan pemrosesan yang tepat sehingga saya tidak aman dan digunakan stackalloc
"?
sumber
System.Numbers
menggunakannya banyak referensiource.microsoft.com/#mscorlib/system/…Jawaban:
Satu-satunya alasan untuk menggunakan
stackalloc
adalah kinerja (baik untuk komputasi atau interop). Dengan menggunakanstackalloc
alih-alih array yang dialokasikan heap, Anda membuat lebih sedikit tekanan GC (GC perlu berjalan lebih sedikit), Anda tidak perlu menyematkan array ke bawah, ini lebih cepat untuk mengalokasikan daripada heap array, dan secara otomatis dibebaskan pada metode exit (array yang dialokasikan heap hanya dibatalkan alokasinya saat GC berjalan). Juga dengan menggunakanstackalloc
alih-alih pengalokasi asli (seperti malloc atau .Net yang setara), Anda juga mendapatkan kecepatan dan deallokasi otomatis saat keluar cakupan.Dari segi kinerja, jika Anda menggunakan,
stackalloc
Anda sangat meningkatkan kemungkinan cache ditemukan pada CPU karena lokalitas data.sumber
Saya telah menggunakan stackalloc untuk mengalokasikan buffer untuk pekerjaan DSP [dekat] realtime. Itu adalah kasus yang sangat spesifik di mana kinerja harus sekonsisten mungkin. Perhatikan ada perbedaan antara konsistensi dan throughput keseluruhan - dalam hal ini saya tidak khawatir dengan alokasi heap yang terlalu lambat, hanya dengan non determinisme pengumpulan sampah pada saat itu dalam program. Saya tidak akan menggunakannya dalam 99% kasus.
sumber
stackalloc
hanya relevan untuk kode yang tidak aman. Untuk kode terkelola, Anda tidak dapat memutuskan di mana mengalokasikan data. Jenis nilai dialokasikan di tumpukan per default (kecuali jika merupakan bagian dari jenis referensi, dalam hal ini dialokasikan di heap). Jenis referensi dialokasikan di heap.Ukuran tumpukan default untuk aplikasi .NET vanilla biasa adalah 1 MB, tetapi Anda dapat mengubahnya di header PE. Jika Anda memulai utas secara eksplisit, Anda juga dapat menyetel ukuran yang berbeda melalui overload konstruktor. Untuk aplikasi ASP.NET ukuran tumpukan default hanya 256K, yang perlu diingat jika Anda beralih di antara dua lingkungan.
sumber
Stackalloc inisialisasi span. Dalam versi C # sebelumnya, hasil stackalloc hanya dapat disimpan ke dalam variabel lokal pointer. Mulai C # 7.2, stackalloc sekarang dapat digunakan sebagai bagian dari ekspresi dan dapat menargetkan rentang, dan itu dapat dilakukan tanpa menggunakan kata kunci yang tidak aman. Jadi, alih-alih menulis
Span<byte> bytes; unsafe { byte* tmp = stackalloc byte[length]; bytes = new Span<byte>(tmp, length); }
Anda dapat menulis dengan sederhana:
Span<byte> bytes = stackalloc byte[length];
Ini juga sangat berguna dalam situasi di mana Anda memerlukan beberapa ruang awal untuk melakukan operasi, tetapi ingin menghindari mengalokasikan memori heap untuk ukuran yang relatif kecil
Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length]; ... // Code that operates on the Span<byte>
Sumber: C # - All About Span: Menjelajahi Andalan .NET Baru
sumber
Span
sayangnya tidak tersedia di .NET framework 4.7.2 dan bahkan tidak di 4.8 ... Sehingga fitur bahasa baru masih digunakan terbatas untuk saat ini.Ada beberapa jawaban bagus dalam pertanyaan ini tetapi saya hanya ingin menunjukkannya
Stackalloc juga dapat digunakan untuk memanggil API asli
Banyak fungsi native mengharuskan pemanggil mengalokasikan buffer untuk mendapatkan hasil yang ditampilkan. Misalnya, fungsi CfGetPlaceholderInfo di
cfapi.h
memiliki tanda tangan berikut.HRESULT CfGetPlaceholderInfo( HANDLE FileHandle, CF_PLACEHOLDER_INFO_CLASS InfoClass, PVOID InfoBuffer, DWORD InfoBufferLength, PDWORD ReturnedLength);
Untuk memanggilnya di C # melalui interop,
[DllImport("Cfapi.dll")] public static unsafe extern HResult CfGetPlaceholderInfo(IntPtr fileHandle, uint infoClass, void* infoBuffer, uint infoBufferLength, out uint returnedLength);
Anda dapat menggunakan stackalloc.
byte* buffer = stackalloc byte[1024]; CfGetPlaceholderInfo(fileHandle, 0, buffer, 1024, out var returnedLength);
sumber