我有一个相当简单的C#应用程序,它构建了一个大型哈希表。此哈希表的键是字符串,值是整数。
程序运行正常,直到大约1030万个项目被添加到哈希表中,当在将该项目添加到hasbtable的行上引发内存不足错误时。
根据任务经理的说法,我的程序只使用了797mb的内存,而且还有超过2GB的可用内存。它是一台32位的机器,所以我知道一个进程只能使用2gb,但是仍然可以将哈希表扩展到1.2gb左右。
为什么会抛出内存不足错误?
答案 0 :(得分:11)
从理论上讲,你可以获得2GB的进程,但实际情况是它有2GB的连续内存,所以如果你的进程内存碎片化,你就会得到更少的内存。
此外,我怀疑默认情况下大多数数据结构的哈希表在需要增长时会增加一倍,从而在添加引爆项时会产生巨大的增长。
如果你知道它需要提前的大小(或者有一个合理的高估),那么在构造函数中指定容量可能会有所帮助。
或者,如果它在内存中并不重要,那么某种数据库解决方案可能会更好,并且如果它确实达到它无法适应内存的程度,则会给你更大的灵活性。
答案 1 :(得分:4)
可能是由于内存碎片:你仍然有空闲内存但不连续。内存分为页,通常大小为4KB,因此如果分配4 MB,则在进程寻址空间中需要1024个连续内存页 (它们不是< em>物理连续,因为内存是按进程虚拟化的。)
然而,散列表的内存并不是连续的(除非它的实现非常糟糕),所以可能是内存管理器的一些限制......
答案 2 :(得分:3)
使用Process Explorer(www.sysinternals.com)查看流程的虚拟地址空间。与“专用字节”(该进程占用的内存量)相比,虚拟地址空间显示正在使用的最高内存地址。如果碎片很高,它将远远高于“私人字节”。
如果您的应用程序确实需要那么多内存:
答案 3 :(得分:1)
你只是看错了专栏。看一下“提交大小”列,这个应该是2GB左右。
http://windows.microsoft.com/en-us/windows-vista/What-do-the-Task-Manager-memory-columns-mean
答案 4 :(得分:1)
由于Visual Studio调试器试图跟踪您在应用程序中执行的所有操作(断点,引用,堆栈等),因此您运行的程序资源有限。
除此之外,你可能还有更多东西比你想象的还要多 - 垃圾收集器是分层的,并且慢慢收集大型对象非常。
+-------+
| large | collected less often (~1/10+ cycles)
+-+-------+-+ |
| medium | |
+-+-----------+-+ V
| small | collected more often (~1/3 cycles)
+---------------+
注意:这些数字来自记忆,所以请加上一粒盐。
答案 5 :(得分:0)
你应该在数组和链表之间使用像hibrid这样的东西。因为链表每个项目占用的内存多于数组,但是数组需要连续的内存空间。
答案 6 :(得分:0)
我通过取消选中Build选项卡下exe的Project Properties页面中的'Prefer 32-bit'复选框解决了我的问题版本