2010-10-21 89 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(); 
     } 
    } 
}