在 C# 中的 Span 中使用结构体的内联固定大小缓冲区的引用是否安全?

问题描述 投票:0回答:1

考虑以下结构:

internal struct WriteBuffer64
{
    private const int INLINE_BUFFER_SIZE = 64;
    private unsafe fixed byte buffer[INLINE_BUFFER_SIZE];
    private int used;

    public unsafe Span<byte> GetWriteSpan(int toWrite)
    {
        if (used + toWrite > INLINE_BUFFER_SIZE)
            throw new Exception(...);

        int offset = used;
        used += toWrite;
        return MemoryMarshal.CreateSpan(ref buffer[offset], toWrite);
    }

    // ...
}

我想知道这样做是否安全。当装箱或在类类型中使用时,

WriteBuffer
的实例可能位于堆上。因此,我假设本机
byte*
指针(指向固定缓冲区)可能无法安全使用。

但是

Span
怎么样?是否能够将其解释为对托管对象的引用?更一般地说,Spans 中托管对象的引用的魔力是如何发挥作用的?

c# .net garbage-collection
1个回答
0
投票

不。结构体通常在堆栈上分配。这个例子说明了为什么它不安全。

void Main() {
    var span = GetMeSpan();
    var beforeMethodCall = string.Join(" ", span.ToArray());
    Console.WriteLine("Just to use the stack");
    var afterMethodCall = string.Join(" ", span.ToArray());

    Console.WriteLine(beforeMethodCall);
    Console.WriteLine(afterMethodCall);
}

Span<byte> GetMeSpan() {
    var buffer = new WriteBuffer64();
    return buffer.GetWriteSpan(42);
}

输出:

Just to use the stack
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 70
64 203 27 0 0 0 0 0 10 159 84 231 254 7 0 0 160 170 74 66 1 0 0 0 0 0 0 0 0 0 0 0 192 0 206 65 1 0 0 0 13 70
© www.soinside.com 2019 - 2024. All rights reserved.