我正在编写一个检索二进制数据并支持将其一般转换为原始类型的类。它应该尽可能高效。这是它现在的样子:
public abstract class MemorySource {
public abstract Span<byte> ReadBytes(ulong address, int count);
public unsafe bool TryRead<T>(ulong address, out T result) where T : unmanaged {
Span<byte> buffer = ReadBytes(address, sizeof(T));
result = default;
// If the above line is commented, `result = ref <...>` won't compile, showing CS0177.
if (!buffer.IsEmpty) {
result = ref Unsafe.As<byte, T>(ref buffer.GetPinnableReference());
return true;
} else
return false;
}
}
由于我正在使用大量内存,并且我的代码将执行许多小型读取操作。我想尽量减少复制内存的次数。
该ReadBytes
实现将a)在堆上已经存在的数组的一部分上创建一个跨度,或者b) stackalloc
一个缓冲区并用来自远程源的数据填充它(取决于我将使用的数据)。关键是,它不会自己在堆上分配任何东西。
我希望我的TryRead<T>
方法返回对跨度内存的类型化引用,而不是将该内存复制到新值中,我想知道这是否可能。我注意到我不能在不初始化参数的情况下为参数赋值ref
,out
但我可以在之后,如果我们假设我正在分配一个引用,这毫无意义。
我想我要问的是,这段代码到底发生了什么?我是返回对现有值的引用,还是将该值复制到新的堆栈分配的值中?堆栈分配和堆分配跨度的行为会有什么不同?T
如果使用堆分配的跨度,GC 会知道在移动数据时更新类型的引用吗?