2010-10-21 3 views
3

Я написал следующую программу, цель которой - создать файл с размером выдачи с некоторыми случайными данными в нем. Программа отлично работает и делает то, что она должна делать. Однако я не понимаю, почему он потребляет 5 ГБ оперативной памяти (см. Снимок экрана моего диспетчера задач). Хотя я пишу файл со случайными данными, я не создаю новые объекты. Что мне не хватает? Я бы ожидал, что эта программа вообще не будет иметь памяти.Использование FileStream и памяти

Большая проблема, я сейчас является то, что в середине на генерацию файла, машина умирает ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     CreateFile("test.dat", 10 * 1024 * 1024); 
    } 

    public static void CreateFile(string path, long approximativeFileSizeInKb) 
    { 
     RandomNumberGenerator randomNumber = RandomNumberGenerator.Create(); 

     byte[] randomData = new byte[64 * 1024]; 

     int numberOfIteration = 0; 
     randomNumber.GetNonZeroBytes(randomData); 

     using (FileStream fs = File.Create(path, 64 * 1024)) 
     { 
      while (numberOfIteration++ * 64 < approximativeFileSizeInKb) 
      { 
       fs.Write(randomData, 0, randomData.Length); 
      } 
     } 
    } 
} 

alt text alt text

+0

Я просто попробовал вашу программу, и после начала я вижу увеличение ~ 1 ГБ. Затем использование памяти остается там до конца. – Gonzalo

+0

Gonzalo - Рад это слышать ... Но на диске все еще много памяти для записи? Вы x86 или x64? – Martin

+0

Большая проблема, с которой я столкнулся сейчас, заключается в том, что в середине процесса генерации файла машина умирает ... – Martin

ответ

3

Измените строку, которая гласит:

using (FileStream fs = File.Create(path, 64 * 1024)) 

к

using (FileStream fs = File.Create(path, 64 * 1024, FileOptions.WriteThrough)) 

и посмотреть, как это делает для вас.

+0

Удивительный! С этим флагом, ОЗУ остается супер-плоской ...: ДИ доволен. Кажется, немного медленнее думал .. – Martin

+0

Это классический компромисс скорости и пространства. ускоряйте настройку вашего второго параметра на более чем 64 Кбайт. Хотя старайтесь держать его на границе 4Kb, чтобы соответствовать размеру страницы памяти Windows по умолчанию. –

+0

Ничего себе, вся эта оперативная память и намеренно ее не использует. не нажимайте это часто на ответ. –

0

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

Используемая память действительно немного больше; вы генерируете 10 МБ-файл (в кусках по 64 КБ) и используете около 5 ГБ памяти для этого. Есть ли что-то еще в этой программе, чем в фрагменте кода? Вы используете его несколько раз?

+0

Это на самом деле 10 ГБ (внимательно прочитайте код), что объясняет, что кеширование на компьютере имеет много неиспользуемой памяти. – Lucero

1

Windows, похоже, использует кэширование файловой системы ... это не приложение

0

Как Гонсало, я побежал ваш код на моей системе и видел только увеличение 1Гб использования памяти.

Есть ли у вас антивирус? AV может сканировать файл .dat, поскольку он записывается, в результате чего данные буферизуются в памяти во время сканирования, что приводит к огромному увеличению использования памяти. Если вы подозреваете, что AV является частью проблемы, попробуйте изменить расширение файла на другое, отличное от .dat (например .txt).

Еще одна вещь, которую нужно попробовать - это добавить вызов fs.Flush() после fs.Write (...).

+0

У меня нет AV. Я изменил имя файла на TXT и добавил Flush. Никаких изменений в поведении. :( – Martin

5

Операции с файловой системой всегда буферизуются ОС.

Вы вызываете FileSystem.Write быстрее, чем ваше оборудование может обрабатывать записи, поэтому ОС кэширует все ваши записи.

Даже если вы вызвали FileSystem.Flush, вы все равно писали бы быстрее, чем ваше оборудование может обрабатывать записи.

Получить более быструю подсистему жесткого диска. Предпочтительный RAID-контроллер с большим количеством встроенной памяти, подключенной к большому массиву RAID 5 или 6 с серверными жесткими дисками с кешами 64 МБ с буферизацией записи.

(Чтобы облегчить это поведение добавить флаг FileOptions.WriteThrough к вашему File.Create вызова.)

1

Я кусочкам это вместе с различных сайтов .... Вопрос в том, для Windows все еще кэширует все даже writethrough вариант.Таким образом, ваша «свободная» память уменьшается, если вы используете стандартный FileStream, что может быть проблематичным, если вы пытаетесь делать определенные вещи с чрезвычайно большими файлами и одновременно захватывать высокоскоростные данные. У Windows все еще есть файлы, кэшированные, когда вы закрываете приложение, кстати. Это хорошо для файлов, которые вы хотите написать и забыть о ... что, по-видимому, не кажется, что вам нужно.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 
using System.Runtime.InteropServices; 
using Microsoft.Win32.SafeHandles; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     [DllImport("KERNEL32", SetLastError = true)] 
     public extern static int CloseHandle(IntPtr hObject); 
     [DllImport("kernel32", SetLastError = true)] 
     public static extern unsafe IntPtr CreateFile(
      string FileName,   // file name 
      uint DesiredAccess,  // access mode 
      uint ShareMode,   // share mode 
      IntPtr SecurityAttributes, // Security Attr 
      uint CreationDisposition, // how to create 
      uint FlagsAndAttributes, // file attributes 
      IntPtr hTemplate // template file 
      ); 
     static void Main(string[] args) 
     { 
      const uint FILE_FLAG_NO_BUFFERING = 0x20000000; 
      const uint FILE_FLAG_WRITE_THROUGH = 0x80000000; 
      Random r = new Random(0); 
      IntPtr f = CreateFile(@"e:\test\temp.bin", 
          (uint)FileAccess.Write, 
          (uint)FileShare.None, 
          IntPtr.Zero, 
          (uint)FileMode.Create, 
           FILE_FLAG_NO_BUFFERING, 
          IntPtr.Zero); 
      using (FileStream fs = new FileStream(f,FileAccess.Write,false,1024*1024)) 
      { 
       int blocksize = 1024 * 1024; 
       byte[] val = new byte[blocksize]; 
       for (int i = 0; i < blocksize; i++) 
       { 
        val[i] = 1; 
       } 
       while (true) 
       { 
        for (int i = 0; i < 1000; i++) 
        { 
         for (int j = 0; j < blocksize; j++) 
         { 
          fs.WriteByte(val[i]); 
         } 
        } 
        Console.WriteLine("Enter s to stop"); 
        ConsoleKeyInfo k = Console.ReadKey(); 
        if (k.KeyChar == 's') 
        { 
         break; 
        } 
       } 
      } 
      CloseHandle(f); 
      Console.WriteLine("done"); 
      Console.ReadKey(); 
     } 
    } 
} 
Смежные вопросы