FileStream и использование памяти - PullRequest
3 голосов
/ 22 октября 2010

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

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

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

Ответы [ 6 ]

6 голосов
/ 22 октября 2010

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

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

на

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

и посмотрите, как это вам подходит.

5 голосов
/ 22 октября 2010

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

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

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

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

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

1 голос
/ 11 февраля 2012

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

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();
        }
    }
}
1 голос
/ 22 октября 2010

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

0 голосов
/ 22 октября 2010

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

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

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

0 голосов
/ 22 октября 2010

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

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

...