处置NativeMemory<T>时,应将其视为托管还是非托管资源?
关于NativeMemory的资源处置类型判定
首先,.NET官方推荐的Dispose模式核心实现如下:
protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { // TODO: 释放托管状态(托管对象) } // TODO: 释放非托管资源(非托管对象),并在下方重写终结器 // TODO: 将大字段设为null _disposed = true; }
相关代码实现
NativeMemory 托管包装类
using System.Runtime.InteropServices; using Whatever.Extensions; namespace XYZ.Extensions; public sealed class NativeMemory<T> : DisposableAsync where T : unmanaged { public unsafe NativeMemory(uint count, uint alignment = 1) { ArgumentOutOfRangeException.ThrowIfZero(alignment); Length = count * (uint)sizeof(T); Pointer = (nint)NativeMemory.AlignedAlloc(Length, alignment); Manager = new NativeMemoryManager<T>((T*)Pointer, (int)Length); Manager.Memory.Span.Clear(); } public NativeMemoryManager<T> Manager { get; } public uint Length { get; } public nint Pointer { get; } protected override ValueTask DisposeAsyncCore() { DisposeNative(); return ValueTask.CompletedTask; } protected override void DisposeNative() { DisposePointer(); } private unsafe void DisposePointer() { NativeMemory.AlignedFree(Pointer.ToPointer()); } }
NativeMemoryManager 内存管理器
using System.Buffers; namespace ISO9660.Extensions; public sealed unsafe class NativeMemoryManager<T>(T* pointer, int length) : MemoryManager<T> where T : unmanaged { private T* Pointer { get; } = pointer; private int Length { get; } = length; protected override void Dispose(bool disposing) { // NOP } public override Span<T> GetSpan() { return new Span<T>(Pointer, Length); } public override MemoryHandle Pin(int elementIndex = 0) { ArgumentOutOfRangeException.ThrowIfNegative(elementIndex); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(elementIndex, Length); return new MemoryHandle(Pointer + elementIndex); } public override void Unpin() { // NOP } }
Disposable 辅助类
using System; #nullable disable namespace Whatever.Extensions { public abstract class Disposable : IDisposable { protected bool IsDisposed { get; set; } public void Dispose() { this.Dispose(true); GC.SuppressFinalize((object) this); } protected virtual void Dispose(bool disposing) { if (this.IsDisposed) return; this.DisposeNative(); if (disposing) this.DisposeManaged(); this.IsDisposed = true; } protected virtual void DisposeManaged() { } protected virtual void DisposeNative() { } ~Disposable() => this.Dispose(false); } }
DisposableAsync 辅助类
using System; using System.Threading.Tasks; #nullable enable namespace Whatever.Extensions { public abstract class DisposableAsync : Disposable, IAsyncDisposable { public async ValueTask DisposeAsync() { DisposableAsync disposableAsync = this; await disposableAsync.DisposeAsyncCore().ConfigureAwait(false); GC.SuppressFinalize((object) disposableAsync); } protected virtual async ValueTask DisposeAsyncCore() { await new ValueTask().ConfigureAwait(false); } } }
问题
处置NativeMemory<T>时,应将其视为托管资源还是非托管资源?
解答
要明确这个问题,得拆分NativeMemory<T>内部的资源类型:
- 非托管资源部分:通过
NativeMemory.AlignedAlloc分配的内存是典型的非托管资源——CLR垃圾回收器无法追踪这类内存,必须手动调用NativeMemory.AlignedFree释放,否则会造成内存泄漏。这部分操作不受disposing参数影响,无论主动调用Dispose还是终结器触发,都必须执行释放。 - 托管资源部分:
NativeMemoryManager<T>是托管对象,但它的Dispose方法是空实现,且仅封装了非托管内存指针,没有持有需要额外释放的托管资源,所以不需要特殊的托管资源释放逻辑。
回到NativeMemory<T>的处置逻辑:它当前的实现是正确的——将非托管内存释放放在DisposeNative中,无论disposing是true还是false都会执行,符合Dispose模式处理非托管资源的要求,且无需在DisposeManaged中添加额外逻辑。
总结:NativeMemory<T>本身是托管包装类,但核心持有非托管资源(对齐分配的内存),处置时重点是处理非托管资源的释放,其托管成员无需额外处置操作。
内容的提问来源于stack exchange,提问作者aybe
相关产品推荐
相关产品推荐

