c# 如果span<T>(memory<T>) 引用堆栈上的缓冲区会发生什么

joe*_*joe 5 c# memory stack-overflow .net-standard

.NET Standard 2.1 引入了一项新功能,您可以在其中“控制”内存块而不是复制它们:SpanMemory

在文档示例中,我注意到可以引用堆栈缓冲区:

byte data = 0;
Span<byte> stackSpan = stackalloc byte[100];
for (int ctr = 0; ctr < stackSpan.Length; ctr++)
   stackSpan[ctr] = data++;
Run Code Online (Sandbox Code Playgroud)

据我所知,一个进程的堆栈内存是有限的(1MB 或 4MB),我们无法手动释放它。

所以我想创建一个Memory<T>orSpan<T>会以某种方式“固定”堆栈上的内存位置,以便我们可以索引它?但这不是可能导致堆栈溢出的堆栈泄漏的潜在情况吗?由于堆栈上的数组应该与Memory<T>or一样长Span<T>

Ale*_*kov 6

这是安全的,因为 Span 的生命周期将与堆栈分配的数组相同或更短。

您不能至少直接将结果分配给stackallocto Memory<T>(我认为即使是不安全的代码也无济于事 - C#:将通用指针转换为数组)因此将其范围限定为Span<T>.

根据您发布的链接,跨度生命周期与其定义的范围相关联:

Span<T>是一个在堆栈上而不是在托管堆上分配的引用结构。Ref struct 类型有许多限制,以确保它们不能提升到托管堆,

请注意,这ref struct会禁止某些操作,包括您应该关注的操作 -Span<T>从分配堆栈的方法返回。由于结果跨度将同时(或更早)被销毁,然后包含由stackalloc.

   static Span<byte> MySpan()
   {
        Span<byte> span = stackalloc byte[100];
        // error CS8352: Cannot use local 'span' in this context because it may 
        // expose referenced variables outside of their declaration scope
        return span;
    }
Run Code Online (Sandbox Code Playgroud)

这也在 MSDN 杂志文章(2018 年 1 月)C# - All About Span: Exploring a New .NET Mainstay by Stephen Toub 中有所介绍。