敞开生长之旅!这是我参加「日新计划 12 月更文挑战」的第12天,点击查看活动概况
stackalloc 表达式
stackalloc
表达式在栈(stack
)上分配内存块。
在办法履行期间创建的栈中分配的内存块会在办法回来时自动丢掉。不能显式开释运用 stackalloc
分配的内存。stackalloc
分配的内存块不受废物回收的影响,也不用经过 fixed
语句固定。
栈内存,栈内存开辟快速高效但资源有限,一般束缚1M。
能够将 stackalloc
表达式的结果分配给以下任一类型的变量:
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分配内存块
赋值给 System.Span<T>
或 System.ReadOnlySpan<T>
类型的变量不用运用不安全上下文(unsafe context
)。
能够在表达式允许的任何地方运用stackalloc
,并且在需要分配内存
时,推荐尽可能的运用 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 分配 指针类型
如下示例,对于指针类型,stackalloc
表达式只能用于本地变量声明的初始化中。
unsafe
{
int length = 3;
int* numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
}
运用指针类型,有必要运用不安全上下文(unsafe context
)。
stackalloc分配内存的注意点
仓库可用的内存数量是有限的,如果分配太多内存,则可能发生StackOverflowException
异常。因此需要注意以下几点:
- 束缚运用
stackalloc
分配的内存数量。
例如,如果预期的缓冲区巨细低于某个束缚,则能够在仓库上分配内存;否则,请运用所需长度的数组。如下代码所示:
const int MaxStackLimit = 1024;
Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
stack 上可用内存数量取决于代码的履行环境。
- 避免在循环内部运用
stackalloc
。在循环外部allocate
分配内存块,并在循环内部重用。
新分配内存的内容是未界说的。有必要在运用之前初始化。 比如,能够运用 Span<T>.Clear
办法设置所有的元素项为类型T
的默认值。
也能够运用数组初始化器界说新分配内存的内容。
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]
时,其类型只能对错保管类型。(虽然在运用和形式上,非保管类型与C#的原始类型几乎没有区别,但,还是能够了解下)。
以下类型的归于或也归于非保管类型:
-
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, orbool
- 任何
enum
类型 - 任何
pointer
类型 - 任何 只包含非保管类型字段的用户界说(
user-defined
)的struct
类型
运用非保管泛型束缚unmanaged
,指定类型参数为非指针、不可为空的非保管类型。
仅包含非保管类型字段的结构结构类型(constructed struct type
)也对错保管的。如下示例所示,DisplaySize<T>()
办法的泛型束缚为unmanaged
,在调用时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
泛型结构Coords<T>
能够对错保管和保管结构类型。当然也能够束缚为非保管类型,如下:
public struct Coords<T> where T : unmanaged
{
public T X;
public T Y;
}
参考
- stackalloc expression
- Unmanaged types