我编写的内存密集型程序内存不足:抛出OutOfMemory异常。在尝试减少内存使用量的过程中,我开始调用GC.GetTotalMemory(true)(将总内存使用量写入调试文件),这会触发垃圾收集。
出于某种原因,在调用此函数时,我不会再出现内存不足异常。如果我再次删除调用(保持其他所有内容相同),则会再次抛出异常。根据我的理解,当内存压力增加时,会自动调用来收集垃圾,所以我不明白这种行为。
任何人都可以解释为什么只有在没有GC.collect调用时才抛出内存不足异常?
我正在使用VS 2010,但我正在将应用程序转移到框架3.5。我相信碎片整理确实会导致我的问题。
我做了一些测试:当抛出异常时,对GC.gettotalmemory的调用告诉我我正在使用~800 * 10 ^ 6个字节。但是,任务管理器告诉我应用程序使用1700 MB。相当大的差异。我现在计划只分配一次内存,并且永远不会释放任何大型数组但重用它们。幸运的是,我的程序让我可以毫不费力地完成这个任务。
答案 0 :(得分:4)
我通过更智能的内存管理解决了这个问题。特别是根据http://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/
上的建议使用CustomList答案 1 :(得分:2)
您的应用是否以完整CPU运行?我很确定只有在应用程序空闲时才会发生自动垃圾收集。否则,您必须运行手动循环。
答案 2 :(得分:1)
我很确定内存不足不强制进行垃圾回收。这可能听起来令人难以置信的不直观,但我认为这是有充分理由的。它可以防止程序进入死亡螺旋,它不断地试图找到更多的空间并将所有物体牢牢地塞进第2代。从中非常很难再次恢复。
传递给GetTotalMemory()的 true 参数会强制进行完整的垃圾回收。我猜想这会释放大对象堆中足够的空间来满足内存分配。这当然只能工作一次。如果你的程序一直在运行,吞噬超过1.5千兆字节或超过已经消耗的内存,那么OOM就在眼前。这个时候没有办法恢复。幸存下来的OOM需要激烈的措施。
你需要一个好的内存分析器来找出真正正在进行什么。项目中的非托管C ++始终是内存泄漏的沃土。非管理型,总是难以解决问题。
答案 3 :(得分:0)
GC.Collect
仅仅是一个释放未使用内存的“建议” - 它并不能保证它的释放。
[编辑]
看起来,虽然在我多年前学习JVM时曾经如此,但在.NET中可能并非如此。 MSDN Library表示GC.Collect
“强制立即对所有世代进行垃圾收集。”关于这个here的好东西(无论如何)。
答案 4 :(得分:0)
如果您拥有占用大量内存的非托管资源,垃圾收集器将无法真正识别内存压力。如果在终结器中清理这些资源,那么强制收集将导致释放那些非托管资源,而如果不强制收集,则垃圾收集器可能没有意识到它需要收集。
如果您正在执行大型非托管分配,您可以使用GC.AddMemoryPressure告诉GC,因此在决定是否运行集合时可以将其考虑在内。
答案 5 :(得分:0)
我正在浏览Microsoft Connect网站,我看到错误报告,其中人们正在提出相同的声明。声称是OutOfMemoryException
正在发生,可以通过定期调用GC.Collect
来解决。我看到一个report来自垃圾收集器团队的首席工程师回复并说在.NET 4.0中修复了一个错误,它应该解决大对象堆的碎片问题。这就是我问你正在使用什么版本的原因。
你当然可能偶然发现了垃圾收集器中的一个错误。与所有与GC相关的问题一样,这可能与版本有关。
我的建议是: