C#使用stackalloc分配堆棧內(nèi)存和非托管類型詳解
stackalloc 表達(dá)式
stackalloc
表達(dá)式在棧(stack
)上分配內(nèi)存塊。
在方法執(zhí)行期間創(chuàng)建的棧中分配的內(nèi)存塊會(huì)在方法返回時(shí)自動(dòng)丟棄。不能顯式釋放使用 stackalloc
分配的內(nèi)存。stackalloc
分配的內(nèi)存塊不受垃圾回收的影響,也不必通過 fixed
語句固定。
棧內(nèi)存,棧內(nèi)存開辟快速高效但資源有限,通常限制1M。
可以將 stackalloc
表達(dá)式的結(jié)果分配給以下任一類型的變量:
stackalloc 分配 System.Span<T> 或 System.ReadOnlySpan<T> 類型
int length = 3; Span<int> numbers = stackalloc int[length]; for (var i = 0; i < length; i++) { numbers[i] = i; }
將stack分配內(nèi)存塊
賦值給 System.Span<T>
或 System.ReadOnlySpan<T>
類型的變量不必使用不安全上下文(unsafe context
)。
可以在表達(dá)式允許的任何地方使用stackalloc
,并且在需要分配內(nèi)存
時(shí),推薦盡可能的使用 Span<T>
或 ReadOnlySpan<T>
類型。
int length = 1000; Span<byte> buffer = length <= 1024 ? stackalloc byte[length] : new byte[length];
Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 }; var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6, 8 }); Console.WriteLine(ind); // output: 1
stackalloc 分配 指針類型
如下示例,對(duì)于指針類型,stackalloc
表達(dá)式只能用于本地變量聲明的初始化中。
unsafe { int length = 3; int* numbers = stackalloc int[length]; for (var i = 0; i < length; i++) { numbers[i] = i; } }
使用指針類型,必須使用不安全上下文(unsafe context
)。
stackalloc分配內(nèi)存的注意點(diǎn)
堆棧可用的內(nèi)存數(shù)量是有限的,如果分配太多內(nèi)存,則可能發(fā)生StackOverflowException
異常。因此需要注意以下幾點(diǎn):
- 限制使用
stackalloc
分配的內(nèi)存數(shù)量。
例如,如果預(yù)期的緩沖區(qū)大小低于某個(gè)限制,則可以在堆棧上分配內(nèi)存;否則,請(qǐng)使用所需長度的數(shù)組。如下代碼所示:
const int MaxStackLimit = 1024; Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
stack 上可用內(nèi)存數(shù)量取決于代碼的執(zhí)行環(huán)境。
- 避免在循環(huán)內(nèi)部使用
stackalloc
。在循環(huán)外部allocate
分配內(nèi)存塊,并在循環(huán)內(nèi)部重用。
新分配內(nèi)存的內(nèi)容是未定義的。必須在使用之前初始化。 比如,可以使用 Span<T>.Clear
方法設(shè)置所有的元素項(xiàng)為類型T
的默認(rèn)值。
也可以使用數(shù)組初始化器定義新分配內(nèi)存的內(nèi)容。
Span<int> first = stackalloc int[3] { 1, 2, 3 }; Span<int> second = stackalloc int[] { 1, 2, 3 }; ReadOnlySpan<int> third = stackalloc[] { 1, 2, 3 };
非托管類型 Unmanaged type
在定義指針、stackalloc T[n]
時(shí),其類型只能是非托管類型。(雖然在使用和形式上,非托管類型與C#的原始類型幾乎沒有區(qū)別,但,還是可以了解下)。
以下類型的屬于或也屬于非托管類型:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, orbool
- 任何
enum
類型 - 任何
pointer
類型 - 任何 只包含非托管類型字段的用戶定義(
user-defined
)的struct
類型
使用非托管泛型約束unmanaged
,指定類型參數(shù)為非指針、不可為空的非托管類型。
僅包含非托管類型字段的構(gòu)造結(jié)構(gòu)類型(constructed struct type
)也是非托管的。如下示例所示,DisplaySize<T>()
方法的泛型約束為unmanaged
,在調(diào)用時(shí)Coords<int>
、Coords<double>
作為非托管類型使用:
using System; public struct Coords<T> { public T X; public T Y; } public class UnmanagedTypes { public static void Main() { DisplaySize<Coords<int>>(); DisplaySize<Coords<double>>(); } private unsafe static void DisplaySize<T>() where T : unmanaged { Console.WriteLine($"{typeof(T)} is unmanaged and its size is {sizeof(T)} bytes"); } } // Output: // Coords`1[System.Int32] is unmanaged and its size is 8 bytes // Coords`1[System.Double] is unmanaged and its size is 16 bytes
泛型結(jié)構(gòu)Coords<T>
可以是非托管和托管構(gòu)造類型。當(dāng)然也可以限制為非托管類型,如下:
public struct Coords<T> where T : unmanaged { public T X; public T Y; }
參考
以上就是C#使用stackalloc分配堆棧內(nèi)存和非托管類型詳解的詳細(xì)內(nèi)容,更多關(guān)于C# stackalloc分配堆棧內(nèi)存的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#自動(dòng)給文章關(guān)鍵字加鏈接實(shí)現(xiàn)代碼
這篇文章主要介紹了C#自動(dòng)給文章關(guān)鍵字加鏈接實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2013-12-12深入理解C# abstract和virtual關(guān)鍵字
深入理解C# abstract和virtual關(guān)鍵字,學(xué)習(xí)c#的朋友可以參考下。2011-06-06利用C#實(shí)現(xiàn)將小數(shù)值四舍五入為整數(shù)
在項(xiàng)目的開發(fā)中,遇到一些除法計(jì)算內(nèi)容會(huì)產(chǎn)生小數(shù)值,但是又需要根據(jù)項(xiàng)目的實(shí)際情況將這些小數(shù)內(nèi)容化為整數(shù),所以本文為大家整理了C#實(shí)現(xiàn)將小數(shù)值四舍五入為整數(shù)的方法,希望對(duì)大家有所幫助2023-07-07c#入門之循環(huán)語句使用詳解(for循環(huán)、do/while)
這篇文章主要介紹了c#入門之循環(huán)語句使用詳解,有for循環(huán)和do/while的示例,需要的朋友可以參考下2014-04-04C#使用NPOI實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出功能
這篇文章主要為大家詳細(xì)介紹了C#使用NPOI實(shí)現(xiàn)Excel導(dǎo)入導(dǎo)出功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02