【问题标题】:MemoryMappedFile CreateViewAccessor throws "Not enough storage is available to process this command."MemoryMappedFile CreateViewAccessor 抛出“没有足够的存储空间来处理此命令。”
【发布时间】:2013-03-27 15:17:05
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您是否尝试在处理完 MMF 后致电GC.Collect?该错误通常意味着内存不足。
  • 我们最终编写了自己的映射器,将这个文件的块加载到内存中,因此不需要在内存中拥有一大块可用空间。你可以在gist.github.com/luuksommers/af473efe618d589df951查看它

标签: c# memory-mapped-files


【解决方案1】:
  • 尝试使用 x64 平台处理而不是 x32 平台

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

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

  • 这是另一个关于此类错误的好话题(尽管提到了 VS.Net IDE,它包含了为什么会发生此类错误的详细信息)Not enough storage is available to process this command in VisualStudio 2008 如果您经常需要非常大的内存,这是一个想法,这会导致内存碎片,所以当您仍然有足够的总可用内存时,您没有足够大的可用内存块。

  • 1234563通过一些幸运的编码,它可能会导致 CLR 更好地管理内存;但您需要谨慎做出此类决定。

【讨论】:

    猜你喜欢
    • 2014-06-23
    • 2015-01-22
    • 2012-05-14
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    相关资源
    最近更新 更多