簡體   English   中英

C#巨大的2-Dim數組

[英]C# huge size 2-dim arrays

我需要在C#WinForms中聲明方形矩陣,連續超過20000個項目。 我讀到32位的2GB .Net對象大小限制以及64位操作系統中的相同大小寫。 所以我理解單一答案 - 使用不安全的代碼或使用C ++編譯器構建的獨立庫。

對我來說問題是值得的,因為ushort [20000,20000]小於2GB但實際上我甚至無法分配700MB的內存。 我的限制是650MB,我不明白為什么 - 我有32位WinXP和3GB內存。 我嘗試使用Marshal.AllocHGlobal(700 << 20)但它拋出OutOfMemoryException,GC.GetTotalMemory在嘗試分配內存之前返回4.5MB。

我發現只有很多人說使用不安全的代碼,但我找不到如何在堆中聲明2-dim數組的示例(任何堆棧都不能保存如此大量的數據)以及如何使用指針處理它。 它是不安全的{}括號內的純C ++代碼嗎?

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

編輯:有人可以提供一個使用不安全代碼中的指針處理矩陣的小例子 我知道在32位以下不可能分配更多的空間,但我花了很多時間在谷歌搜索這樣的例子,發現沒什么

為什么要求巨大的二維陣列? 您可以使用例如鋸齒狀數組來模擬這個 - ushort[][] - 幾乎同樣快,並且您不會達到相同的單個對象限制。 你當然還需要buckets-o-RAM,所以暗示x64 ......

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

除此之外 - 您可能想要查看稀疏數組,eta向量和所有爵士樂。

你甚至無法接近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位窗口,分配給每個進程的可尋址內存最多可跳躍到8TB,因此CLR幾乎肯定能夠為陣列使用完整的2Gb分配。

我很開心! :)最近我玩了主題問題 - 嘗試使用數據庫解決它但只發現這種方式是完美的。 Matrix [20000,20000]實現為單表。 即使正確設置了索引,只需要創建超過4億條記錄的時間,我的電腦上大約需要1小時。 這對我來說並不重要。 然后我運行算法來處理該矩陣(需要兩次加入同一個表!)並且在它工作超過半小時后它甚至沒有單步執行。 在那之后,我明白了唯一的方法就是找到一種方法,只在內存中使用這種矩陣,然后再回到C#。

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

正如我在第一篇文章中所說,在32位WinXP下,可以使用2-Dim陣列僅分配大約650MB 使用Win7和64位編譯后的結果也很悲傷 - 不到700MB。

我使用了JAGGED ARRAYS [] []而不是單個2-dim數組[,],結果你可以在下面看到:

在發布模式下編譯為32位應用程序 - WinXP 32bit 3GB phys。 MEM。 - 1.45GB在發布模式下編譯為64位應用程序 - 在VM下為Win7 64位2GB - 7.5GB

- 我用於測試的應用程序源附於此帖子。 我在這里找不到如何附加源文件,所以只需描述設計部分並放在這里手動代碼。 創建WinForms應用程序。 使用默認名稱放置這樣的控件: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

問題解決了我。 伙計們,提前謝謝你們!

如果稀疏數組不適用,可能最好只在C / C ++中使用與內存映射文件相關的平台API: http//en.wikipedia.org/wiki/Memory-mapped_file

如果你解釋了你想要做什么,那將更容易提供幫助。 也許有比一次分配如此大量內存更好的方法。

在這篇偉大的博文中,重新設計也是第一選擇:

BigArray,繞過2GB數組大小限制

本文中建議的選項是:

對於OutOfMemoryException,請閱讀此主題(尤其是nobugz和Brian Rasmussen的回答):
Microsoft Visual C#2008減少加載的dll數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM