MemoryMappedFile CreateViewAccessor抛出“没有足够的存储空间来处理此命令”

本文关键字:存储空间 处理 命令 抛出 CreateViewAccessor MemoryMappedFile | 更新日期: 2023-09-27 18:06:21

我们在MemoryMappedFile中加载一个222MB的文件,用于原始数据访问。该数据使用写方法更新。经过一些计算后,应该将数据重置为文件的原始值。我们目前通过处置类并创建一个新实例来实现。这在很多时候都很顺利,但有时CreateViewAccessor会崩溃,并出现以下异常:

系统。异常:没有足够的可用存储来处理此命令。System.IO.IOException: Not enough storage is available to process this command.

在System.IO.__Error

。WinIOError(Int32 errorCode, String maybeFullPath)在System.IO.MemoryMappedFiles.MemoryMappedView。CreateView(SafeMemoryMappedFileHandle> memMappedFileHandle, MemoryMappedFileAccess访问,Int64偏移量,Int64大小)在System.IO.MemoryMappedFiles.MemoryMappedFile。CreateViewAccessor(Int64 offset, Int64> size, MemoryMappedFileAccess access)

下面的类用于访问内存映射文件:

public unsafe class MemoryMapAccessor : IDisposable
{
    private MemoryMappedViewAccessor _bmaccessor;
    private MemoryMappedFile _mmf;
    private byte* _ptr;
    private long _size;
    public MemoryMapAccessor(string path, string mapName)
    {
        FileInfo info = new FileInfo(path);
        _size = info.Length;
        using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            _mmf = MemoryMappedFile.CreateFromFile(stream, mapName, _size, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false);
        _bmaccessor = _mmf.CreateViewAccessor(0, 0, MemoryMappedFileAccess.CopyOnWrite);
        _bmaccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref _ptr);
    }
    public void Dispose()
    {
        if (_bmaccessor != null)
        {
            _bmaccessor.SafeMemoryMappedViewHandle.ReleasePointer();
            _bmaccessor.Dispose();
        }
        if (_mmf != null)
            _mmf.Dispose();
    }

    public long Size { get { return _size; } }
    public byte ReadByte(long idx)
    {
        if ((idx >= 0) && (idx < _size))
        {
            return *(_ptr + idx);
        }
        Debug.Fail(string.Format("MemoryMapAccessor: Index out of range {0}", idx));
        return 0;
    }
    public void Write(long position, byte value)
    {
        if ((position >= 0) && (position < _size))
        {
            *(_ptr + position) = value;
        }
        else
            throw new Exception(string.Format("MemoryMapAccessor: Index out of range {0}", position));
    }
}

这个问题的可能原因是什么,有没有解决办法/变通办法?

MemoryMappedFile CreateViewAccessor抛出“没有足够的存储空间来处理此命令”

  • 尝试使用x64平台进程代替x32进程

  • 确保每次都手动处置MemoryMapAccessor。根据你的实现,GC将而不是为你调用Dispose——这里有一个很好的解释。

  • 调用Dispose不会使变量为空,因此GC将等待,直到它知道没有人使用这些变量。确保变量在Dispose之后超出作用域,或者简单地将它们标记为null。最简单的情况是处置在你的处置-为什么不标记为空的变量,如果你不需要他们了吗?

  • 这是另一个关于这种错误的好话题(虽然是指VS.Net IDE,它包含了为什么会发生这种错误的细节)在VisualStudio 2008中没有足够的存储来处理这个命令,其中一个想法是,如果你经常需要非常大的内存部分,这会导致内存碎片,所以当你仍然有足够的总空闲内存时,你没有足够大的空闲内存块。

  • 对于您的具体情况,也许只是从文件中读取byte[]数组到内存是一个好主意,尽管不深入涉及非托管资源。通过一些幸运的编码,它可能会导致CLR更好的内存管理;