2013-03-27 2 views
4

Мы загружаем файл 222 МБ в MemoryMappedFile для доступа к необработанным данным. Эти данные обновляются с использованием метода write. После некоторых вычислений данные должны быть сброшены до исходного значения файла. В настоящее время мы делаем это, удаляя класс и создавая новый экземпляр. Это идет хорошо много раз, но иногда CreateViewAccessor падает со следующим исключением:MemoryMappedFile 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 смещение, Int64> размер, MemoryMappedFileAccess доступа)

следующий класс используется для доступа к 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)); 
    } 
} 

Каковы возможные причины этой проблемы и есть ли какое-либо решение/обходное решение?

+0

Вы пытались вызвать «GC.Collect» после утилизации MMF? эта ошибка обычно означает, что памяти недостаточно. –

+0

Мы закончили тем, что создали собственный картограф, который загружает блоки этого файла в память, поэтому не нужно иметь один большой блок свободного пространства в памяти. Вы можете проверить это на https://gist.github.com/luuksommers/af473efe618d589df951 – Luuk

ответ

5
  • Попробуйте использовать платформу x64 и процесс вместо x32 одних

  • , чтобы обеспечить утилизацию MemoryMapAccessor вручную каждый раз. Согласно вашей реализации, GC будет не вызова Dispose для вас - вот великое объяснения об этом Proper use of the IDisposable interface

  • Вызова Dispose не делает ваш переменный нуль, поэтому GC будет ждать до тех пор, пока не понять ни одного, используя эти переменные. Удостоверьтесь, что ваши переменные выходят за рамки после Dispose или просто отмечают их null. Самый простой случай - избавиться от вашего Dispose - почему бы не пометить переменные как null, если они вам больше не нужны? Это позволяет GC съесть их быстрее.

  • Вот еще одна хорошая тема относительно такой ошибки (хотя она упоминается в VS.Net IDE, она содержит сведения о том, почему такая ошибка может произойти) Not enough storage is available to process this command in VisualStudio 2008 Одна из идей, если вам часто нужны действительно большие части памяти, что приводит к фрагментация памяти, поэтому, пока вы все еще имеете достаточную полную свободную память, у вас недостаточно большой части свободной памяти.

  • Для вашего конкретного случая, может быть, идея питания будет просто читать массив byte[] в память из файла, хотя это и не связано с неуправляемыми ресурсами. С некоторой удачной кодировкой это может привести к лучшему управлению памятью с помощью CLR; но вам нужно проявлять осторожность при принятии таких решений.

+1

Спасибо, много хорошей информации здесь! Я попробую некоторые вещи и вернусь к вам. – Luuk

Смежные вопросы