代码之家  ›  专栏  ›  技术社区  ›  Cheburek

C#大尺寸二维阵列

  •  5
  • Cheburek  · 技术社区  · 16 年前

    我需要在C#WinForms中声明一行中有20000多个项的平方矩阵。 我读到关于2GB.Net对象大小限制在32位和同样的情况下,64位操作系统。

    这个问题对我来说是值得的,因为ushort[2000020000]小于2GB,但实际上我甚至不能分配700MB的内存。我的限制是650MB,我不明白为什么-我有32位WinXP和3GB内存。 我尝试使用Marshal.AllocHGlobal(700<&书信电报;20) 但它抛出OutOfMemoryException,GC.GetTotalMemory在尝试分配内存之前返回4.5MB。

    我只发现很多人说使用不安全的代码,但我找不到如何在堆中声明二维数组(任何堆栈都不能保存如此大量的数据)以及如何使用指针处理它的示例。 在不安全的{}括号内是否是纯C++代码?

    请不要问我为什么需要这么大的数组。。。但如果你想-我需要分析文本(例如书籍)并找到很多索引。所以答案是-单词之间的关系矩阵

    编辑:有人能提供一个小的吗 . 我知道在32位下分配更多的空间是不可能的,但我花了很多时间在谷歌上搜索这样的例子,却一无所获

    6 回复  |  直到 16 年前
        1
  •  5
  •   Marc Gravell    16 年前

    ushort[][] 几乎

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

    除此之外-你可能想看看稀疏数组,eta向量,以及所有这些。

        2
  •  4
  •   Andrew O'Reilly    16 年前

    在32位窗口中,即使2Gb分配也无法接近的原因是,CLR中的数组是在连续内存中布局的。在32位Windows中,地址空间非常有限,在进程的虚拟地址空间中找不到像2Gb这样的漏洞。您的实验表明,可用地址空间的最大区域是650Mb。移动到64位Windows至少应该允许您使用完整的2Gb分配。

    请注意,32位Windows上的虚拟地址空间限制与计算机中的物理内存量无关,以3Gb为例。相反,限制是由CPU用来寻址内存地址的位数引起的。32位Windows使用32位来访问每个内存地址,这使得总的可寻址内存空间为4gb。默认情况下,Windows为自己保留2Gb,并为当前运行的进程提供2Gb,因此您可以看到为什么CLR找不到2Gb分配。通过一些技巧,您可以更改操作系统/用户分配,使Windows只为自己保留1Gb,并为正在运行的进程提供3Gb,这可能会有所帮助。然而,在64位窗口中,分配给每个进程的可寻址内存会跳到8 TB,因此在这里,CLR几乎肯定能够为阵列使用全部2Gb分配。

        3
  •  2
  •   Cheburek    16 年前

    即使正确设置索引,在我的电脑上创建超过4亿条记录所需的时间也只有1个小时,这对我来说并不重要。 然后我运行算法来处理那个矩阵(需要两次才能连接同一个表!)在它工作了半个多小时后,它甚至没有迈出一步。 从那以后,我明白了唯一的方法就是找到一种只在内存中使用这种矩阵的方法,然后再回到C。

    我创建了试验应用程序来测试内存分配过程,并使用不同的结构来确定分配过程在何处停止。

    650MB 在32位WinXP下。 700兆。

    我使用了锯齿状数组[],而不是单个2维数组[],结果如下:

    在发布模式下编译为32位app-WinXP 32位3GB phys。记忆- 1.45GB

    --我用来测试的应用程序的来源附在这篇文章后面。 我在这里找不到如何附加源文件,所以只需描述设计部分,并把这里的手册代码。 创建WinForms应用程序。 使用默认名称设置控件: 在.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
  •  0
  •   Community Mohan Dere    9 年前

    对于OutOfMemoryException,请阅读以下线程(特别是nobugz和Brian Rasmussen的回答):
    Microsoft Visual C# 2008 Reducing number of loaded dlls

        6
  •  0
  •   Dirk Vollmar    16 年前

    在这篇博文中,重新设计也是首选:

    BigArray, getting around the 2GB array size limit