Memory<T>.Span中的内存是如何unpinned的?

How is the memory unpinned in Memory<T>.Span?

我认为下面两段代码应该是等价的:

// first example
string s = "Hello memmory";
ReadOnlyMemory<char> memory = s.AsMemory();
using (MemoryHandle pin = memory.Pin())
{
    Span<char> span = new Span<char>(pin.Pointer, 1);
    Console.WriteLine(span[0]);
}

// second example
ReadOnlySpan<char> span2 = memory.Span;
Console.WriteLine(span2[0]);

两个代码都将打印 "H"。

我不明白的是第二个例子中内存的unpinning在哪里

据我所知,字符串是在堆上分配的,MemoryHandle 固定它并从指针创建 Span。 MemoryHandle.Dispose 取消固定内存。

我相信 memory.Span 也必须固定内存,否则 span 无法访问指针。但是第二个例子中的内存是如何解绑的呢?

Span 只存在于当前方法线程的栈上,而不存在于它的堆上,因此只要你在那里使用它,它就会存在。到目前为止很清楚。

现在是有趣的部分:

明确的事实是 memory.Span 的结果不是固定的,而是仅通过使用 Span<T> 中的 ref T 引用的由 GarbageCollector 观察到。

只要你的记忆还在,你的跨度也会存在,这就是你的跨度。

参考文献:

https://msdn.microsoft.com/en-us/magazine/mt814808.aspx?f=255&MSPPError=-2147217396 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-struct-types

最后一个假设是不正确的:memory.Span不需要固定内存,因为垃圾收集器知道它的底层引用。如果您想将指针传递给本机 API.

,固定是独立可用的