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

时间:2013-03-27 15:17:05

标签: c# memory-mapped-files

我们在MemoryMappedFile中加载了一个222MB的文件,用于原始数据访问。使用write方法更新此数据。经过一些计算后,数据应重置为文件的原始值。我们目前通过部署类并创建新实例来实现这一点。 这种情况很好,但有时CreateViewAccessor崩溃时出现以下异常:

  

System.Exception:没有足够的存储空间来处理此命令。    ---> System.IO.IOException:没有足够的存储空间来处理此命令。

     

at 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)

以下类用于访问memorymapped文件:

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));
    }
}

导致此问题的可能原因是什么?是否有解决方案/解决方法?

1 个答案:

答案 0 :(得分:5)

  • 尝试使用x64平台处理代替x32

  • 确保每次都手动处理MemoryMapAccessor。根据您的实施情况,GC会为您调用Dispose - 这里有很好的解释Proper use of the IDisposable interface

  • 调用Dispose不会使您的变量为null,因此GC会等到它理解没有人使用这些变量。在Dispose之后确保您的变量超出范围,或者只是将它们标记为null。最简单的情况是在您的Dispose中处理 - 如果您不再需要它们,为什么不将变量标记为null?这样GC就可以更快地吃掉它们。

  • 这是关于此类错误的另一个好主题(虽然它被称为VS.Net IDE,它包含可能发生此类错误的详细信息)Not enough storage is available to process this command in VisualStudio 2008如果你经常需要真正的大部分内容内存,导致内存碎片,所以很快你仍有足够的总可用内存,你没有足够大的可用内存块。

  • 对于您的具体情况,将文件中的byte[]数组读入内存可能是一个美食的想法,尽管不会深入涉及非托管资源。通过一些幸运的编码,它可以通过CLR实现更好的内存管理;但是你需要谨慎做出这样的决定。