У меня есть код, который открывает файл сопоставления памяти и выставляет 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
, но я не уверен, где находится граница между небезопасными и безопасными ресурсами.Одна ссылка , которую я обнаружил , говорит, что 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
, если _isDisposed
верно, чтобы избежать ошибок UAF и повреждения памяти.
Какой из них является правильным шаблоном удаления, когда небезопасные указатели выставляются с SafeMemoryMappedViewHandle
?Кроме того, стоит ли устанавливать для поля Memory
значение null во время утилизации?