2010-04-07 42 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