使用AcquirePointer时,处置SafeMemoryMappedViewHandle的正确方法是什么?

时间:2018-09-30 10:18:20

标签: c# dispose memory-mapped-files unsafe

我有一些代码可以打开一个内存映射文件,并公开一个ReadOnlySlice<T>用于许多解析操作。下面是简化的类代码:

public MemoryMappedViewAccessor Accessor { get; }
public SafeMemoryMappedViewHandle Handle { get; }
public byte* Memory;
private long _size;

public Parser(MemoryMappedFile mappedFile, long offset, long size)
{
    _size = size;
    Accessor = mappedFile.CreateViewAccessor(offset, _size, MemoryMappedFileAccess.Read);
    Handle = Accessor.SafeMemoryMappedViewHandle;
    unsafe
    {
        Handle.AcquirePointer(ref Memory);
    }
}

public ReadOnlySlice<T> GetSpan<T>(int offset, int size)
{
    return new ReadOnlySpan<T>(chunk.Memory, _size).Slice(offset, size);
}

/* other functions exposing various Slice<T> over this */

显然,这需要我的班实现IDisposable,但我不确定不安全资源和安全资源之间的界限在哪里。一个reference I found表示SafeMemoryMappedViewHandle是一个托管资源,应该这样处理,但是没有提到ReleasePointer会如何变化,或者是否ReleasePointer应该是在Dispose之前调用。

我的看法是,以下两种Dispose模式是我的选择:

选项1-将所有内容视为托管内容

private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_isDisposed)
    {
        if (disposing)
        {
            Accessor.Dispose();
            Handle.ReleasePointer(); // is this even needed?
            Handle.Dispose();
        }

        _isDisposed = true;
    }
}

public void Dispose()
{
    Dispose(true);
}

选项2-将指针释放视为不受管理

private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_isDisposed)
    {
        if (disposing)
        {
            Accessor.Dispose();
        }

        Handle.ReleasePointer();
        Handle.Dispose();

        _isDisposed = true;
    }
}

~FileChunk()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

在这两种情况下,如果ObjectDisposedException为true,我都将在检查逻辑中添加一个检查以抛出_isDisposed,以避免UAF错误和内存损坏。

SafeMemoryMappedViewHandle中暴露不安全的指针时,其中哪些是正确的处置模式?另外,是否值得在处置期间将Memory字段设置为null?

0 个答案:

没有答案