Ign*_*cia 1 .net memory out-of-memory virtual-memory
在一个内存饥渴的应用程序我正在开发我面临OutOfMemoryExceptions.我希望虚拟内存永远不会有这种异常.为什么如果需要更多RAM而不是可用操作系统不使用HD作为RAM?
Chr*_*ens 10
您可以通过多种方式获取OutOfMemoryException.在32位窗口中,进程可以使用2GB的虚拟地址空间(我相信在64位应用程序中它是1TB).请记住,这不是 RAM,它是完全不同的,因此是"虚拟的".所以忘了RAM.RAM所做的就是让事情变得更快.Windows内存管理器决定程序使用的内存是在RAM还是磁盘中.当你打开许多程序时,较少的内存被加载到物理RAM中,而更多的内存将被加载到磁盘上.你的表现会很糟糕,但你不会有OOM例外.
在.NET中获取OOM异常的最常见方法是尝试分配足够大量的数据(类似于字节数组),其中没有足够的连续内存页面可用于映射它,这是我怀疑的地方你的问题在于.这意味着即使您正在请求将虚拟地址空间增加到2GB以上的新对象,也可能会出现内存不足异常.
"可是等等!" 有人可能会说,"当垃圾收集器运行时,内存会被压缩,因此堆末端总会有连续的空间!"
大多数情况下都是如此.GC将从堆中收集,它实际上可以被认为是两个堆,小对象堆(SOH)和来自大对象堆(LOH)的堆.大多数对象,因为它们相当小,将存在于主要的世代堆中.但是,如果对象高于某个大小阈值(这是85K,但可能已经更改),则将其分配给LOH.
当内存是从LOH回收,它不压缩像SOH.对于LOH中的存储器来说,压缩是太昂贵了.内存分配虽然足够昂贵,但应用程序性能会受到影响.这意味着您的堆可以并且经常会变得支离破碎(在.NET 4.0运行时,与2.0兼容版本相比,这已大大改进).
* = object - = free space |**|***|*|**|*|******|****|**|*****|*******|**|*|***|*****|***|**|-- ^ ^ ^ ^ ^ ^ ^ marked for GC
* = object - = free space |--|***|*|-- -|******|****|**|-----|*******|--|*|***|-----|***|----
现在我想分配一个数组********.运行时将尝试在其中找到适合的位置.它没有.运行时有什么作用?好吧,假设上面代表你的整个2GB虚拟空间并且不能分配更多内存,将抛出OOM异常.你有免费的内存页面,但不够连续.
我不知道你的应用程序做了什么,但这里有几件事要检查:
你在静态类型成员中分配大数组吗?只要静态成员指向该对象,即使您不再使用它,它也永远不会是GC.静态成员位于类型对象上,只有在卸载AppDomain时才会释放它们.
您是否根据用户或其他输入获得分配大小?例如,如果您正在读取一个告诉您条目长度的文件头,您是否验证条目的大小是否正确?我自己遇到了一个错误,我在一个文件中读错了地址并试图分配2TB的内存.验证疯狂.
如果要分配大型阵列,您真的需要吗?将数据加载到内存并不能保证您的性能会提高.请记住,您的程序是分配虚拟内存空间,而不是ram.如果您正在阅读文件,是否正在挑选并选择您完全阅读哪些内容以及哪些内容正在流式传输?
我能想到的只有几件事,而且肯定不全面.除了尝试处理超过2GB的地址空间之外,耗尽内存的另一种方法是整页文件,但这种情况不太常见.
一些有用的工具:
WinDbg(包含在Windows SDK中,作为Windows调试工具的一部分) - 您可以使用它来查看有关堆的统计信息.我最喜欢的是!dumpheap -stat和!dumpheap -type [type].我可以使用它来快速查找使用大量内存的类型.
CLRProfiler - 比WinDbg更易于使用,功能更少.它为您提供了很好的内存分配图形,您甚至可以看到应用程序退出时剩余的GC句柄数.图形按类型着色,因此它概述了堆中使用最多内存的类型.
| 归档时间: |
|
| 查看次数: |
1095 次 |
| 最近记录: |