散列表 - 内存不足

4
我正在我的C#应用程序中使用Hashtable。我加载了数百万个键,但当应用程序超过3.7GB的RAM时,它会给我一个"内存不足"的异常。
我使用的是x64操作系统,计算机有16GB的RAM。我想这可能是x86的限制。我将构建类型更改为x64,但仍然出现错误。
在.NET中,对象是否有最大内存大小限制?我能做些什么来使用所有的内存?
谢谢, 安德鲁

1
对于这么大的数据集,您可能需要使用一些基于磁盘(或部分基于磁盘)的解决方案。将那么多的数据加载到内存中并不是好的做法。看看 BerkeleyDB,它有 .NET 绑定并且是免费的。 - Tamas Czinege
2
RAM是无关紧要的;RAM只是一个缓存,用于加快内存访问。相关的稀缺资源是可用地址空间 - Eric Lippert
Eric Lippert:我不知道你是在评论问题还是我的评论,但我的意思是(除了有限的地址空间),从磁盘加载那么多数据需要非常长的时间(特别是如果它正在被分页)。 - Tamas Czinege
1
对的,我的意思是,一个以“我正在用尽内存但我有足够的RAM”开头的问题表明了对实际运行情况的误解。你可以拥有256兆字节的RAM,但仍然有20个程序每个使用500兆字节的地址空间;机器会很慢,但你不会用完地址空间。而你可以拥有14 GB 的空闲RAM,但仍然会用完地址空间。RAM的数量与用完地址空间的问题完全无关;它只与性能有关。 - Eric Lippert
5个回答

8

+1,我还在打字的时候你就已经超越我了。另请参阅:http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx - Sapph
@Sapph,谢谢你提供的链接,我正在寻找它来补充这个答案 =) - Rubens Farias

7
使用 Dictionary<,> 替代 HashTable。在 HashTable 中,键和值都是对象,因此如果它们是值类型,则会进行装箱。 Dictionary 可以使用值类型作为键和/或值,这将使用更少的内存。例如,如果您使用 int 作为键,在 HashTable 中每个键值对将使用 28 字节,而在 Dictionary 中仅使用 4 字节。

如果键和值都是值类型并且使用小于 8 字节,则 Dictionary 将能够容纳比 HashTable 更多的项。


1

这篇文章指出,.NET将单个对象的大小限制为两个千兆字节。


1

我发现这个页面非常有用,因为我在VB .net中遇到了完全相同的问题。我创建了一些非常大的哈希表,当尝试创建它们时,我的应用程序会抛出内存不足异常。

我尝试了“Guffa”的建议,在一个较小的示例哈希表上使用字典,结果字典实际上增加了大小!

他的建议让我思考我实际上正在写入哈希表的内容。所以我看了看这个页面,决定我实际上不需要存储类型为Long的数据,Integer已经足够了。我知道我可能在告诉所有的大师们一个显而易见的事情,但是我能够通过将变量声明为整数而不是长整型来将结果序列化的哈希表(总共12个)从81.9Mb减少到69.4Mb。

这实际上并没有解决我的问题,但肯定会改善将它们加载回内存所需的时间。


0

这个问题与您系统中的物理RAM数量无关,也与是否编译为x64位无关。.NET现在也不再限制对象为2GB。您可能需要调查一下.NET 4.5的大对象堆(Large Object Heap)以获取更多信息。您之所以会收到“内存不足”的错误是因为进程无法映射您请求的连续内存区域的大小。

Eric Lippert在这个问题上有一篇很好的博客文章,我注意到他评论了这个问题,但不幸的是没有回答它。

所以这就是答案:接受这个事实,即您使用此实现寻求的内存大小并不容易获得,并通过将其分解成较小的内存块来解决您的问题。

我曾经遇到过同样的问题,不得不采取同样的方法。使用嵌套数组可能有所帮助,或者将数据分成多个逻辑组件并创建一系列较小的哈希表。


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