2010-10-21 148 views
3

我写了下面的程序,其目的是为了创造一个给定大小的文件与它的一些随机数据。该程序工作正常,并做它应该做的。但是,我不明白为什么它会消耗5GB的RAM(请参阅我的任务管理器的屏幕截图)。当我用随机数据写文件时,我不创建新的对象。我错过了什么?我希望这个程序根本不会记忆。的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

我刚试过你的程序,一开始我看到增加了〜1GB。然后内存使用停留在那里直到结束。 – Gonzalo 2010-10-21 20:23:40

+0

Gonzalo - 很高兴听到......但是这仍然有很多RAM在磁盘上写入?你是x86还是x64? – Martin 2010-10-21 20:29:13

+0

我现在面临的一个大问题是,在文件生成过程中,机器正在死亡...... – Martin 2010-10-21 20:40:40

回答

3

更改一行字:

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

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

,并看看如何为你做。

+0

太棒了!随着那面旗帜,RAM保持超级平坦...:DI很开心,似乎慢了一点...... – Martin 2010-10-21 21:24:56

+0

这是经典的速度与空间的平衡,你可能会重新获得一些速度通过调整你的第二个参数大于64Kb尽管试图保持它在4Kb的边界,以匹配Windows默认的内存页面大小 – 2010-10-21 21:28:45

+0

哇,所有的RAM和故意不使用它。这是犯罪。不要鞭挞它经常在一个答案。 – 2010-10-21 22:47:41

0

通过FileStream保持内存缓冲区,因而您的程序尽可能快地输出。您的程序可以充填数据到缓冲区远不止于此缓冲速度更快,可以写入磁盘,这就是内存跳跃进来

实际使用似乎不是有点过,但更多的内存。你生成一个10MB的文件(64KB块),并使用大约5GB的内存来完成。除了代码片段中的内容,这个程序还有其他什么吗?你是否多次运行它?

+0

它实际上是10GB(仔细阅读代码),这将解释机器的缓存有很多未使用的内存。 – Lucero 2010-10-21 20:31:04

1

的Windows似乎是使用文件系统缓存......它不是应用

0

贡萨洛一样,我跑我的系统上的代码,只看到在内存使用量的增加1GB。

你有抗病毒是否已开启?该AV可以扫描.dat文件,因为它是被写入,使数据在内存中,而扫描发生,这会导致内存使用量大幅增加缓冲。如果您怀疑AV是问题的一部分,请尝试将文件扩展名更改为.dat以外的内容(例如.txt)。

另一件事是尝试加入fs.Write后fs.Flush()的调用(...)。

+0

我没有AV。我将文件名更改为TXT并添加了Flush。行为没有变化。 :( – Martin 2010-10-21 20:47:13

5

文件系统写入始终由OS缓冲。

要调用FileSystem.Write比你更快的硬件可以处理写入,因此OS是缓存所有的写操作。

即使你叫FileSystem.Flush,你仍然会被写入速度比你的硬件可以处理写入。

获得速度更快的硬盘子系统。 Preferrable的RAID控制器与许多上连接到一个大RAID 5或6阵列与具有写入缓冲设置64MB的高速缓存服务器基于硬盘驱动器板上存储器。

(为了缓解这种现象的标志FileOptions.WriteThrough添加到您的通话File.Create)

1

我拼凑了一起,从各个网站....问题是Windows仍然缓存的一切,即使写式选项。因此,如果您使用标准的FileStream,那么您的“Free”内存就会下降,如果想要使用极大的文件进行某些操作并同时捕获高速率的数据,则可能会产生问题。当你关闭你的应用时,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(); 
     } 
    } 
}