views:

67

answers:

7

I've written the following program which purpose is to create a file of a give size with some random data in it. The program works fine and does what it's suppose to do. However, I don't understand why it consumes 5GB of RAM (see screenshot of my Task Manager). While I am writing the file with random data, I am not creating new objects. What am I missing? I would expect this program to take no memory at all.

The big problem I have right now is that in the middle on the file generation, the machine is dying...

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

A: 

The FileStream maintains a memory buffer, allowing your program to output as fast as it can. Your program can stuff data into the buffer MUCH faster than that buffer can be written to disk, which is where the memory jump comes in.

The memory actually used does seem more than a little off, though; you're generating a 10MB file (in 64KB chunks) and using about 5GB of memory to do so. Is there anything else to this program than what's in the code snippet? Are you running it multiple times?

KeithS
It's actually 10GB (read the code carefully), which would explain the caching going on of the machine has lots of unused memory.
Lucero
A: 

Windows seems to be using file system caching... it's not the app

Lucero
A: 

You have a lot of RAM, more than you need. Until you gave it something useful to do: storing that large file in the file system cache. The benefit is that your program runs very fast, even though it is writing an enormous file. That works up to a point until the cache fills up because the disk cannot keep up. Then the perf of your program falls off a cliff, only being able to write as fast as the disk lets it.

Hans Passant
The big problem I have right now is that in the middle on the file generation, the machine is dying... So Windows is more than just using the RAM.
Martin
What does "dying" mean? Motherboard on fire?
Hans Passant
Windows is not responding.
Martin
Hmm, too bad, smoke is easier to diagnose. Turn off your virus scanner, search indexer, whatever else wants a piece of the action. This question belongs on superuser.com
Hans Passant
@Hans: rofl, yes, that does tend to help a diagnosis. The prognosis usually isn't very good though.
KeithS
A: 

Like Gonzalo, I ran your code on my system and only saw a 1GB increase in memory usage.

Do you have anti-virus turned on? The AV may be scanning the .dat file as it's being written, causing the data to be buffered in memory while the scan takes place, which causes the huge increase in memory usage. If you suspect AV to be part of the problem, try changing the file extension to something other than .dat (e.g. .txt).

Another thing to try is adding a call to fs.Flush() after fs.Write(...).

Chris R. Timmons
I have no AV. I changed the file name to TXT and added Flush. No change in the behavior. :(
Martin
A: 

Lucero is right.

I executed the code and definitely the console application is not using the memory, it keeps at 23 Mb. The memory is used by Windows Cache. To confirm it, I debugged and paused the process at some point. What I saw was how memory usage slowly goes down. Note that a paused process can't free any memory at all.

Gerardo Grignoli
A: 

Change your line which reads:

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

to

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

and see how that does for you.

Jesse C. Slicer
Awesome! With that flag, the RAM stays super flat... :D I am happy. It seems a little slower thought..
Martin
It's the classic trade-off of speed vs. space. You can likely re-gain some speed by tweaking your 2nd parameter to be more than 64Kb. Though try to keep it on a 4Kb boundary to match Windows default memory page size.
Jesse C. Slicer
Wow, all that RAM and intentionally not using it. This is criminal. -1, and I don't whip that out often on an answer.
Hans Passant
Really? For directly addressing his exact need, it gets voted down? I don't see downvotes on the other answers which give the same advice.
Jesse C. Slicer
I needed something that doesn't eat up all the RAM on the machine. Thank you Jesse. You answered my question.
Martin
+3  A: 

File system writes are always buffered by the OS.

You are calling FileSystem.Write faster than your hardware can handle the writes, thus the OS is caching all of your writes.

Even if you called FileSystem.Flush, you would still be writing faster than your hardware can handle the writes.

Get a faster hard disk subsystem. Preferrable an RAID controller with lots of on board memory connected to a large RAID 5 or 6 array with server based hard drives with 64MB caches set with write buffering.

(To alleviate this behavior add the flag FileOptions.WriteThrough to your File.Create call.)

Pasquel von Savant