.NET4.0 GC不会收集未使用的空间=> OutOfMemoryException异常

时间:2013-06-12 14:08:06

标签: .net garbage-collection out-of-memory profiler

我们有WinForm应用程序处理大量的地图数据。我们有一个缓存(一个简单的Hashtable),我们存储经常访问的地图数据,以加快操作。虽然我们确实限制了缓存的大小,但是任务管理器显示了不断增长的内存消耗,最后我们得到了OutOfMemoryException。 奇怪的是内存分析器和GC.GetTotalMemory以及我们自己的对象大小计算都说同样的事情:我们的缓存从不使用比我们的限制集更多的内存。 如果我们禁用缓存,我们的系统工作正常:在处理地图数据期间,它会达到峰值几秒钟,但之后会恢复正常。

内存分析器很好地显示使用的空间(以绿色表示)与我们的缓存大小完全对应,但大部分预留内存未使用
在分析会话期间,我们拍摄了4个内存快照:

  • 内存snapshot1:缓存开启(最大缓存大小为300MB)
  • 内存snapshot2:缓存关闭
  • 内存snapshot3:再次缓存(最大缓存大小为300MB)
  • 内存snapshot4:再次缓存

观看下面的颜色编码。为什么那些巨大的未使用空间(蓝色)没有被要求退回? 调用GC.Collect没有区别

Memory profiling session, turning cache on and off

1 个答案:

答案 0 :(得分:0)

正如汉斯在评论中指出的那样,根本问题是记忆碎片化。在创建我们的缓存对象(相当大的对象)期间,我们有许多中等大小的瞬态对象在大型永久对象之间创建间隙。一旦我们通过重用减少了瞬态对象的数量,碎片就会急剧下降。

正如您在图表中看到的,使用的:未使用空间的比率为1:2。修改后 比例是8:1。