4

生データにアクセスするために、MemoryMappedFile に 222MB のファイルをロードしています。このデータは write メソッドを使用して更新されます。いくつかの計算の後、データをファイルの元の値にリセットする必要があります。現在、クラスを破棄して新しいインスタンスを作成することでそれを行っています。これは多くの場合うまくいきますが、CreateViewAccessor が次の例外でクラッシュすることがあります。

System.Exception: このコマンドを処理するのに十分な記憶域がありません。---> System.IO.IOException: このコマンドを処理するのに十分なストレージがありません。

System.IO.__Error.WinIOError (Int32 errorCode、おそらくフルパスの文字列) で System.IO.MemoryMappedFiles.MemoryMappedView.CreateView (SafeMemoryMappedFileHandle > memMappedFileHandle、MemoryMappedFileAccess アクセス、Int64 オフセット、Int64 サイズ) で System.IO.MemoryMappedFiles.MemoryMappedFile.CreateViewAccessor ( Int64 オフセット、Int64 > サイズ、MemoryMappedFileAccess アクセス)

次のクラスは、メモリマップ ファイルにアクセスするために使用されます。

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

この問題の考えられる原因は何ですか?解決策/回避策はありますか?

4

1 に答える 1

5
  • x32 の代わりにx64 プラットフォームとプロセスを使用してみてください

  • 毎回 MemoryMapAccessor を手動で破棄してください。あなたの実装によれば、GC はあなたのためにDisposeを呼び出しません。

  • Dispose を呼び出しても変数は null にならないため、GC はこれらの変数を使用している人がいなくなるまで待機します。Dispose の後に変数がスコープ外にあることを確認するか、単に null とマークします。最も簡単なケースは、Dispose で破棄することです。もう変数が必要ない場合は、変数を null としてマークしないのはなぜですか? これにより、GC はそれらをより速く食べることができます。

  • このようなエラーに関する別の良いトピックがあります (VS.Net IDE に言及されていますが、そのようなエラーが発生する理由の詳細が含まれています) VisualStudio 2008 でこのコマンドを処理するのに十分なストレージがありません。その結果、メモリの断片化が発生するため、まだ十分な空きメモリがあるうちに、十分な大きさの空きメモリのチャンクがなくなります。

  • あなたの特定のケースでは、byte[]管理されていないリソースに深く関与するわけではありませんが、配列をファイルからメモリに読み込むだけでよいでしょう。いくつかの幸運なコーディングにより、CLR によるメモリ管理が向上する可能性があります。しかし、そのような決定には注意が必要です。

于 2013-03-28T08:45:51.647 に答える