C#应用程序可以使用多少RAM?

4
我有一个应用程序,其中包含非常大的DataTable对象、非常大的数组等。
目前我的内存使用量低于2GB。
在32位系统上,当我的应用程序生成4个1GB大小的数组时会发生什么?
它会崩溃吗?
我知道CLR中存在2GB对象大小限制,但对于许多大型对象呢?
我试图进行测试,声明了几个大数组,但当它们为空时,它们似乎不使用RAM。我没有尝试填充它们,而是决定在这里提问。

6
为什么不试试呢? - Mels
了解更多关于 .net,也许您需要一些存储,比如数据库。 - Roar
@Roar,数据来自SQL Server,但有些东西在SQL中计算起来太复杂了。 - Kamil
1
真的吗?现在都2013年了,这还能是个问题?赶紧切换到x64吧。虽然仍然存在对单个数组大小的限制,但“可以使用多少RAM?”只是“你能在机器上放下多少RAM?”的简单问题。 - Marc Gravell
2
@ken2k 当开发人员花费时间思考这个问题的成本比一开始就使用x64更高时,就会出现这种情况。那个时间可能是在2009年左右。 - Marc Gravell
显示剩余7条评论
5个回答

6

64位应用程序,包括托管的应用程序,可以访问大内存。

32位应用程序最多具有4GB的虚拟地址空间。实际上,它们默认获得2GB。/LARGEADRESSAWARE应用程序可以使用boot.ini中的/3gb获得3GB,或在WoW64上运行时获得4GB。

即使在x64平台上,托管应用程序也无法分配任何单个大于2GB的对象,包括数组。

但是,不管你可用的VA量是多少:操作一个+2GB的DataTable对象是行不通的。使用能够快速处理和操作大量数据并具有智能分页功能的存储引擎。适合此工作的有RedisCassandra甚至传统的RDBMS。

即使您决定直接在内存中操作数据,也需要比DataTable更智能的格式。


我之前不知道WoW64中的32位应用程序可以访问4GB的内存。这很有趣,谢谢。 - Marc Gravell
仅限于amd64。Itanium WoW64不支持,但这是一些鲜为人知且不必要的派对谈资。Itanium... - Remus Rusanu

4

所有32位应用程序的内存限制为2GB。因此,无论如何分配RAM,您都将在2GB处耗尽。

如果需要更多内存,您需要在64位系统上运行它并编译为64位。

  • 使用LARGEADDRESSAWARE,32位应用程序可以使用高达3GB的内存。感谢Marc Gravell在评论中提醒我这一点。

2
对于 .Net 进程,在达到 2GB 限制之前,它会崩溃(OutOfMemoryException)。 - ken2k
1
实际上,进程(包括.NET进程)可以在x86上使用3GB,如果您设置了“LARGEADDRESSAWARE”PE头文件(假设您的操作系统启用了3GB开关,这通常很简单)。 - Marc Gravell
从技术上讲,你可以使用3GB,但在32位系统中,需要应用程序和操作系统都选择使用。因此,考虑到64位处理器是多么常见,如今这并不是真正有用的。偶尔有用的是在64位计算机上具有大地址感知能力的32位应用程序。 - CodesInChaos
@MarcGravell 谢谢,我忘记了 LARGEADDRESSAWARE - Frazell Thomas
@FrazellThomas 请参阅http://blogs.msdn.com/b/tom/archive/2008/04/10/chat-question-memory-limits-for-32-bit-and-64-bit-processes.aspx。 - ken2k
显示剩余2条评论

1
如果使用的 RAM 超过了可寻址的(或拥有的)RAM,你将会收到一个 System.OutOfMemoryException 异常。尝试运行以下代码以查看:
        List<byte[]> foo = new List<byte[]>();
        for (int i = 0; i < 10000; ++i )
            foo.Add(new byte[1024*1024*1024]);

1

是的,它会崩溃。这是我尝试过的示例代码:

class Program
{
    static byte[] arr = new byte[1024 * 1024 * 1024];
    static byte[] arr2 = new byte[1024 * 1024 * 1024];
    static byte[] arr3 = new byte[1024 * 1024 * 1024];
    static byte[] arr4 = new byte[1024 * 1024 * 1024];
    static void Main(string[] args)
    {            
        Console.ReadKey();
    }
}

这是一个相当原始的测试程序。除非全部数据同时强烈可达,否则它可能已经被垃圾回收部分回收,因此不会崩溃。
您也可以将它们局部化。然而,如果您进行了发布构建(使用代码优化),以下位运算可以完美运行,因为未使用的数组(或通常的变量)可能会被优化掉:
static void Main(string[] args)
{
    byte[] arr = new byte[1024 * 1024 * 1024];
    byte[] arr2 = new byte[1024 * 1024 * 1024];
    byte[] arr3 = new byte[1024 * 1024 * 1024];
    byte[] arr4 = new byte[1024 * 1024 * 1024];
    Console.ReadKey();
}

调试版本(没有代码优化)中,上述位也会因为OutOfMemoryException而崩溃。
相比之下,字段当然不能被省略。因此,无论编译器是否对代码进行了优化,第一个示例都会崩溃。

谢谢,我刚意识到我应该在我的测试中使用 static... - Kamil
@Kamil 我认为这不仅仅是关于 static 的问题。请查看我的编辑后的答案。 - Matthias Meid

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接