2010-04-07 20 views
5

我需要連續超過20000項申報在C#中的WinForms方陣。 我讀到的32位2GB .NET對象大小限制,並在64位操作系統相同的情況。 因此,當我理解單個答案時 - 正在使用不安全的代碼或使用C++編譯器構建的獨立庫。C#巨大的大小2調光陣列

這個問題對我來說是值得,因爲USHORT [20000,20000]越小則2GB的,但實際上我不能分配甚至內存700MB。我的限制是650MB,我不明白爲什麼 - 我有32位WinXP和3GB內存。 我試圖用Marshal.AllocHGlobal(700 < < 20),但它拋出OutOfMemoryException異常,GC.GetTotalMemory試圖分配內存,然後返回4.5MB。

我發現只有很多人說使用不安全的代碼,但我找不到例如如何在堆中聲明2維數組(任何堆棧不能保證數據的如此巨大數額),以及如何使用指針,它的工作。 它是不安全的{}括號內的純C++代碼?

PS。請不要問爲什麼我需要這麼龐大的數組......但是如果你想 - 我需要分析文本(例如書籍)並找到很多索引。所以答案是 - 詞與詞之間的關係

編輯的矩陣:可能有人請提供使用指針在不安全的代碼矩陣工作的一小例子。我知道,在32位是不可能的分配更多的空間,但我在谷歌上搜索這樣的例子花了很多時間,沒有發現任何

+0

爲什麼?你想做什麼? – SLaks 2010-04-07 15:35:36

+0

相關問題http://stackoverflow.com/questions/1087982/ – 2010-04-07 15:41:45

+0

我添加了一些鏈接到我的答案示例代碼。 – 2010-04-08 13:18:23

回答

1

我太高興了! :)最近我玩弄了主題問題 - 試圖用數據庫解決它,但只發現這種方式是非常完美的。矩陣[20000,20000]被實現爲單個表。 即使正確設置索引時間,只需創建超過4億條記錄,我的電腦也只需1小時左右。這對我來說並不重要。 然後我運行算法來處理這個矩陣(需要兩次加入同一張表!),並且在它工作了半個多小時後,它甚至沒有任何一步。 之後,我明白,唯一的辦法就是找到一種方法,只在內存中使用這種矩陣,然後再回到C#。

我創建了試用應用程序來測試內存分配過程,並確定使用不同結構的分配過程停止在哪裏。

正如我在第一篇文章說,這是可以利用2 - 昏暗的陣列只有約下,WinXP的32位650MB分配。 使用Win7和64位編譯後的結果也令人傷心 - 小於700MB。

我用交錯數組[] [],而不是單一的2維數組[,]和結果可以參見下面的:

在Release模式編譯爲32位應用程序 - 的WinXP 32位3GB的PHY。 MEM。 - 1.45GB 在Release模式爲64位應用程序編譯 - Win7的64位2GB VM下 - 應用我用於測試的7.5GB

--Sources被附加到此信息。 我無法在這裏找到如何附加源文件,所以只描述設計部分,並放在這裏手動代碼。 創建WinForms應用程序。 放在這樣的形式與contols默認名稱: 1按鈕,1周的NumericUpDown和1個列表框 在.cs文件添加下面的代碼並運行。

private void button1_Click(object sender, EventArgs e) 
     { 
      //Log(string.Format("Memory used before collection: {0}", GC.GetTotalMemory(false))); 
      GC.Collect(); 
      //Log(string.Format("Memory used after collection: {0}", GC.GetTotalMemory(true))); 
      listBox1.Items.Clear(); 
      if (string.IsNullOrEmpty(numericUpDown1.Text)) { 
       Log("Enter integer value"); 
      }else{ 
       int val = (int) numericUpDown1.Value; 
       Log(TryAllocate(val)); 
      } 
     } 

     /// <summary> 
     /// Memory Test method 
     /// </summary> 
     /// <param name="rowLen">in MB</param> 
     private IEnumerable<string> TryAllocate(int rowLen) { 
      var r = new List<string>(); 
      r.Add (string.Format("Allocating using jagged array with overall size (MB) = {0}", ((long)rowLen*rowLen*Marshal.SizeOf(typeof(int))) >> 20)); 
      try { 
       var ar = new int[rowLen][]; 
       for (int i = 0; i < ar.Length; i++) { 
        try { 
         ar[i] = new int[rowLen]; 
        } 
        catch (Exception e) { 
         r.Add (string.Format("Unable to allocate memory on step {0}. Allocated {1} MB", i 
          , ((long)rowLen*i*Marshal.SizeOf(typeof(int))) >> 20)); 
         break; 
        } 
       } 
       r.Add("Memory was successfully allocated"); 
      } 
      catch (Exception e) { 
       r.Add(e.Message + e.StackTrace); 
      } 
      return r; 
     } 

     #region Logging 

     private void Log(string s) { 
      listBox1.Items.Add(s); 
     } 

     private void Log(IEnumerable<string> s) 
     { 
      if (s != null) { 
       foreach (var ss in s) { 
        listBox1.Items.Add (ss); 
       } 
      } 
     } 

     #endregion 

問題爲我解決。夥計們,先謝謝你!

5

爲什麼需要一個龐大的2-d陣列?你可以用這個模擬,例如,交錯數組 - ushort[][] - 幾乎一樣快,你不會碰到相同的單對象限制。您仍然需要當然桶-O-RAM,所以64是暗示...

 ushort[][] arr = new ushort[size][]; 
     for(int i = 0 ; i < size ; i++) { 
      arr[i] = new ushort[size]; 
     } 

除了這 - 你可能想看看稀疏陣列,ETA-載體,以及諸如此類。

+0

我還試圖以同樣的方式使用鋸齒狀排列,但得到OutOfMemoryException異常 - 我不知道哪一步 - 我認爲近650MB的東西:) – Cheburek 2010-04-07 15:51:25

+0

@ 4eburek - 好奇,但我們很難複製你的設置,很遺憾。你應該能夠獲得更多的信息,但是在這裏,轉移到x64會更好。 – 2010-04-07 15:56:14

+0

@Marc:交錯數組比2D陣列 – 2010-04-07 15:59:06

0

如果稀疏數組不適用,它可能會更好,只是與有關內存映射文件平臺的API做它在C/C++:http://en.wikipedia.org/wiki/Memory-mapped_file

+1

.NET 4.0框架附帶使用內存映射文件的類。 http://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles(VS.100).aspx – dtb 2010-04-07 16:12:04

+0

@dtb:我認爲使用關係數據庫要慢得多,不過謝謝。 – Cheburek 2010-04-07 16:54:09

+0

@dtb:很高興知道! – Codism 2010-04-07 16:56:52

0

如果你解釋你正在嘗試這樣做會更容易幫幫我。也許有更好的辦法,一次分配如此巨大的內存量。

重新設計也選擇頭號這個偉大的博客文章:

BigArray, getting around the 2GB array size limit

在這篇文章中提出的選項有:

+0

謝謝你的回答。是的,我已經看到BigArray,但沒有嘗試 - 看起來像使用鋸齒狀數組。正如我在之前的回答中所寫的,我嘗試使用鋸齒形數組 - 它們在初始化階段慢了一點,但即使如此,我也無法分配所需的全部內存 - 它會拋出OutOfMemory異常。 最後一個想法出現了 - 可能是我的操作系統實例有問題,需要嘗試另一臺計算機。因爲我無法解釋爲什麼當其他人談論2GB時我甚至無法分配700Mb – Cheburek 2010-04-07 15:58:52

4

即使在32位Windows中的2Gb分配也不能接近的原因是CLR中的數組佈局在連續內存中。在32位Windows中,你有這樣一個有限的地址空間,你會發現在這個進程的虛擬地址空間中沒有任何東西像2Gb洞。您的實驗表明,可用地址空間的最大區域是650Mb。轉移到64位Windows應至少允許您使用完整的2Gb分配。

請注意,32位Windows上的虛擬地址空間限制與您的計算機中的物理內存量無關,在您的情況下爲3Gb。相反,限制是由CPU用於尋址內存地址的位數引起的。不出所料,32位Windows使用32位來訪問每個內存地址,從而給出4Gbytes的總可尋址內存空間。默認情況下,Windows爲自己保留2Gb併爲當前正在運行的進程提供2Gb,因此您可以看到爲什麼CLR將找不到像2Gb分配的任何內容。有一些技巧,你可以改變操作系統/用戶分配,以便Windows只爲自己保留1Gb,並給出可能幫助的運行過程3Gb。但是,對於64位窗口,分配給每個進程的可尋址內存跳至8 TB,因此CLR在這裏幾乎肯定能夠爲陣列使用完整的2Gb分配。

+0

我試圖使用64位Windows7而沒有成功。但它是在同一個WinXP下的虛擬PC上,所以我不能保證結果是正確的 – Cheburek 2010-04-07 16:05:16

+0

這不是我熟悉的環境,但有一點需要檢查,就是你的代碼被編譯爲可以作爲本地x64可執行文件運行在64位Windows上。此MSDN頁面http://msdn.microsoft.com/en-us/library/ms241064%28VS.80%29.aspx提供了更多信息。 – 2010-04-07 16:21:02

+0

在win7下,我使用VS2010,並在配置中管理選定的發佈模式和x64類型的處理器。這是快速的答案,但我需要驗證是否有所有需要的步驟來編譯64位平臺 – Cheburek 2010-04-07 17:00:52