C#内存相关类型理解
In .NET world, there are three types of memory you may be interested:
- Managed heap memory, such as an array;
- Stack memory, such as objects created by stackalloc;
- Native memory, such as a native pointer reference.
Each type of memory access may need to use language features that are designed for it:
To access heap memory, use the fixed (pinned) pointer on supported types (like string), or use other appropriate .NET types that have access to it, such as an array or a buffer; To access stack memory, use pointers with stackalloc; To access unmanaged system memory, use pointers with Marshal APIs. You see, different access pattern needs different code, no single built-in type for all contiguous memory access.
readonly struct Memory<T> : IEquatable<Memory<T>>
{
// The highest order bit of _index is used to discern whether _object is a pre-pinned array.
// (_index < 0) => _object is a pre-pinned array, so Pin() will not allocate a new GCHandle
// (else) => Pin() needs to allocate a new GCHandle to pin the object.
private readonly object? _object;
private readonly int _index;
private readonly int _length;
}
与 Span
- 它可用作类中的字段。
- 它可以跨 await 和 yield 边界使用 。
除了Memory
之外 ,还可以使用 System.ReadOnlyMemory 来表示不可变或只读内存。
- T[]
- MemoryManager
<T> - T=char && object=string
- T=byte/Char8 && object=Utf8String
- ArraySegment
<T>to Memory<T> - Memory
<T>to ReadOnlyMemory<T> - T[] to Memory
<T>
表示一维数组中的一段区域
readonly struct ArraySegment<T> : IList<T>, IReadOnlyList<T>
{
private readonly T[]? _array;
private readonly int _offset;
private readonly int _count;
}
MemoryManager
abstract class MemoryManager<T> : IMemoryOwner<T>, IPinnable
{
public virtual Memory<T> Memory => new Memory<T>(this, GetSpan().Length);
public abstract Span<T> GetSpan();
public abstract MemoryHandle Pin(int elementIndex = 0);
public abstract void Unpin();
protected Memory<T> CreateMemory(int length) => new Memory<T>(this, length);
protected Memory<T> CreateMemory(int start, int length) => new Memory<T>(this, start, length);
protected internal virtual bool TryGetArray(out ArraySegment<T> segment);
}
ref struct是仅在堆栈上的值类型(也被称为嵌入式引用):
- 表现一个顺序结构的布局;(译注:可以理解为连续内存)
- 只能在堆栈上使用 (stack only) 。即用作方法参数和局部变量;
- 不能是类或正常结构的静态或实例成员;
- 不能是异步方法或lambda表达式的方法参数;
- 不能动态绑定、装箱、拆箱、包装或转换。
类型安全和内存安全地表示一段连续内存,它是一个ref struct, 只能在stack上分配内存, 而不能在heap上分配内存, 但是它的实例可以指向托管内存、原生内存或者栈上内存
readonly ref struct Span<T>
{
internal readonly ByReference<T> _pointer;
private readonly int _length;
}