繁体   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