C#使用stackalloc分配堆栈内存和非托管类型详解

 更新时间:2022年12月12日 09:35:41   作者:codemissing  
这篇文章主要为大家介绍了C#使用stackalloc分配堆栈内存和非托管类型详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>

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, or bool
  • 任何 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

以上就是C#使用stackalloc分配堆栈内存和非托管类型详解的详细内容,更多关于C# stackalloc分配堆栈内存的资料请关注脚本之家其它相关文章!

相关文章

  • C#实现简单的字符串加密

    C#实现简单的字符串加密

    这篇文章介绍了C#实现字符串加密的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • Socket不能选择本地IP连接问题如何解决

    Socket不能选择本地IP连接问题如何解决

    本文将介绍一个不要手动,要用程序自动实现 ,可以绑定本地的任何IP地址,有需求的朋友可以参考下
    2012-11-11
  • C#自动给文章关键字加链接实现代码

    C#自动给文章关键字加链接实现代码

    这篇文章主要介绍了C#自动给文章关键字加链接实现代码,有需要的朋友可以参考一下
    2013-12-12
  • 基于C#实现Ping工具类

    基于C#实现Ping工具类

    Ping是一种常用的测试网络连接的工具,可以测试网络延迟和连接状况,以及判断网络是否可用,本文将通过框架类库中的Ping类来实现Ping功能,感兴趣的小伙伴可以了解下
    2023-11-11
  • 深入理解C# abstract和virtual关键字

    深入理解C# abstract和virtual关键字

    深入理解C# abstract和virtual关键字,学习c#的朋友可以参考下。
    2011-06-06
  • 英语单词state与status的区别

    英语单词state与status的区别

    state倾向于condition,是一种延续性的状态。status常用于描述一个过程中的某阶段(phase),类似于C语言中枚举型变量某一个固定的值,这个值属于一个已知的集合。这篇文章主要介绍了英语单词state与status的区别,需要的朋友可以参考下
    2016-11-11
  • 利用C#实现将小数值四舍五入为整数

    利用C#实现将小数值四舍五入为整数

    在项目的开发中,遇到一些除法计算内容会产生小数值,但是又需要根据项目的实际情况将这些小数内容化为整数,所以本文为大家整理了C#实现将小数值四舍五入为整数的方法,希望对大家有所帮助
    2023-07-07
  • c#入门之循环语句使用详解(for循环、do/while)

    c#入门之循环语句使用详解(for循环、do/while)

    这篇文章主要介绍了c#入门之循环语句使用详解,有for循环和do/while的示例,需要的朋友可以参考下
    2014-04-04
  • C#使用NPOI实现Excel导入导出功能

    C#使用NPOI实现Excel导入导出功能

    这篇文章主要为大家详细介绍了C#使用NPOI实现Excel导入导出功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C#把dll分别放在指定的文件夹的方法步骤

    C#把dll分别放在指定的文件夹的方法步骤

    本文主要介绍了C#把dll分别放在指定的文件夹的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05

最新评论