2015-09-28 4 views
1

У меня есть синтаксический анализ данных. Я работаю над явным размером текстовых файлов, которые он читает, и управление памятью является ключевым для хорошей производительности. Стратегия двух частей здесь сначала измеряет, сколько ОЗУ каждого файла будет способствовать сумме, но также необходимо знать, сколько оперативной памяти доступно для приложения в данный момент времени. Если доступно достаточное количество ОЗУ, приложение предпочитает выполнять свою обработку в памяти. В противном случае он переключается на режим, который выполняет все или большинство операций на диске.Измерьте общий объем оперативной памяти, доступной для приложения

Измерение взноса файла на использование памяти быстро и легко:

static Int64 GetSizeInMemory(string path) 
    { 
     //THIS CODE IS SPEEDY 
     Int64 r = ((Func<Int64>)(
        () => 
         { 
          try 
          { 
           using (Stream s = new MemoryStream()) 
           { 
            BinaryFormatter formatter = new BinaryFormatter(); 
            formatter.Serialize(s, File.ReadAllLines(path)); 
            return s.Length; 
           } 
          } 
          catch 
          { 
           //this file is way too big 
           return -1; 
          } 
         } 
       ))(); 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     return r; 
    } 

Однако измерения общего объема памяти, доступной является медленным и трудным. В этом случае я попытался сделать это, захватив ошибку переполнения стека, которая, по моему мнению, должна дать самую надежную цифру.

static Int64 GetMaxAllowedMemory() 
    { 
     //THIS CODE IS SLOW 
     Int64 r = ((Func<Int64>)(
        () => 
         { 
          byte[] b = new byte[]{}; 
          Int64 rs = 0; 
          while (true) 
          { 
           try 
           { 
            Array.Resize<byte>(ref b, b.Length + 1); 
            b[b.Length - 1] = new byte(); 
            rs = b.Length; 
           } catch (Exception e) { 
            break; 
           } 
          } 
          b = null; 
          return rs; 
         } 
       ))(); 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     return r; 
    } 

Есть ли лучший подход, который я должен использовать здесь?

Обращаем внимание,. Я рассмотрел ряд вопросов, подобных этому при переполнении стека, но большинство имеет дело только с получением фигуры для общего объема доступной ОЗУ на компьютере, что не совпадает с Максимальный объем оперативной памяти во время выполнения разрешен для .NET-процесса.

UPDATE

После получения ответа, я придумал следующее, что позволяет мне, чтобы получить общее количество оперативной памяти, доступной для применения.

static Int64 GetMemoryFailPoint() 
    { 
     Int64 r = ((Func<Int64>)(
        () => 
        { 
         int rs = 1; 
         while (true) 
         { 
          try 
          { 
           using (new System.Runtime.MemoryFailPoint(rs)) 
           { 
           } 
          } 
          catch { 
           break; 
          } 
          rs++; 
         } 
         return Convert.ToInt64(rs) * 1000000; 
        } 
       ))(); 
     return r; 
    } 
+1

Для вашего обновления вы, скорее всего, можете сделать свой код намного быстрее, увеличив его, удвоив значение до тех пор, пока оно не сработает, а затем разделите его на 2 и медленно продвигайтесь после этой точки. Кроме того, в [разделе замечаний документации] (https://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint (v = vs.110) .aspx) * «MemoryFailPoint работает с детализацией из 16 МБ. Любые значения меньше 16 МБ обрабатываются как 16 МБ, а другие значения рассматриваются как следующий по величине кратный 16 МБ "*, поэтому' rs ++ 'должен быть' rs + = 16', вы делаете 15 дополнительных проверок который вернет тот же результат. –

+1

Наконец, в MB есть '1 << 20' (' 1048576') байт, поэтому ваш возврат должен быть 'return Convert.ToInt64 (rs) * (1 << 20);'. Для 2048 МБ (2 ГБ) это будет разница в 99 483 648 байтов. –

+0

@ScottChamberlain Спасибо! Я обязательно это рассмотрю. Кроме того, указатель о возврате наиболее полезен. –

ответ

1

Вы можете попробовать использовать MemoryFailPoint класс:

try 
{ 
    using (new System.Runtime.MemoryFailPoint(1024)) // 1024 megabytes 
    { 
     // Do processing in memory 
    } 
} 
catch (InsufficientMemoryException) 
{ 
    // Do processing on disk 
} 

На основе этого original post.

0

Вместо того чтобы прочесть весь файл в памяти и посмотреть, не сработает ли он или нет, вы можете использовать команду MemoryFailPoint, чтобы проверить, достаточно ли свободного места для работы в памяти, используя размер файла на диске.

void ProcessFile(string path) 
{ 
    try 
    { 
     var fileInfo = new FileInfo(path); 
     var fileSizeInMb = (int)(fileInfo.Length >> 20); 
     using (new System.Runtime.MemoryFailPoint(fileSizeInMb)) 
     { 
      // Do processing in memory 
     } 
    } 
    catch (InsufficientMemoryException) 
    { 
     // Do processing on disk 
    } 
} 
+0

К сожалению, это не является точной мерой воздействия файла. Когда я запускаю свою оригинальную функцию для проверки размера в памяти файла, я получаю 166.6 МБ в размере, и используя информацию о файле, я получаю ~ 159 МБ. Это на 7,7 МБ меньше воздействия.Яблоки и апельсины сравнивали бы размер файла с измеренным воздействием на ОЗУ с его считывания в память. –

+0

Ничего. MemoryFailPoint фактически позволяет определить общий объем памяти, доступный до возникновения ошибки переполнения стека. Однако нецелесообразно измерять его по размеру файла, поскольку размер в памяти больше, чем размер на диске. –

+0

@JoshuaDannemann MemoryFailpoint имеет разрешение 16 МБ в любом случае, оно округляется до следующего фрагмента в 16 МБ (см. Документацию), поэтому разница в 7 МБ вряд ли будет иметь огромное значение. –

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