【问题标题】:System.OutOfMemoryException because of Large DictionarySystem.OutOfMemoryException 因为大字典
【发布时间】:2011-03-17 07:19:24
【问题描述】:

我在字典中保存了一个大缓存,其值为IEnumerable<KeyValuePair<DateTime, Double>>。我定期从字典中删除项目并定期将项目添加到字典中。我时不时地得到一个 System.OutOfMemoryException。我想知道为什么垃圾收集器不来救我?

【问题讨论】:

  • 您在缓存中保留了多少项? 1000? 100万?我可以看到大对象堆可能会变得碎片化,并且您将无法在某个点之后增长字典。
  • 您确实意识到存储在字典中的项目不会被垃圾回收吧?至少要等到它们从字典中删除,并发布任何其他参考文献。
  • 我建议运行内存分析器来查看内存中保存了哪些对象。或者获取故障转储并检查堆使用情况。
  • 为什么垃圾收集器不来救我? GC 不会阻止你在脚下开枪;)

标签: c# memory dictionary garbage-collection


【解决方案1】:

请记住,正如@Gabe 所提到的,堆可能会变得支离破碎。即使您可能有空闲内存,它也可能没有足够大的块来分配字典,当它执行调整大小时。

也许您可以使用模式和实践库MSDN Library Link 中的缓存块,这将帮助您实现良好的缓存。也许您可以选择一种不动态分配内存的算法,具有固定数量的条目?

还要注意,如果没有任何内存可供您使用,那么这是缓存大小的问题,而不是垃圾收集器的问题。

【讨论】:

    【解决方案2】:

    很可能 GC 会在很多时候帮助你,但有时你只是超出了它的能力范围。

    绝对清楚,这是Dictionary<DateTime, Double> 还是Dictionary<SomeKeyType, IEnumerable<KeyValuePair<DateTime, Double>>>?如果是后者,那么也许您在其他地方持有引用?

    您的缓存有多大?你有监控来跟踪它吗?是什么让您认为是字典导致了问题?如果您可以控制缓存量,您是否尝试过减小大小?

    【讨论】:

    • 我有一个包含 500 个元素的字典,每个元素都有一个 SomeKeyType 的键,每个 IEnumerable> 有大约 5000 个键值对。所以那是 5000 * 500 大约 2,500,000 KVP。据我所知,DateTime 是 8 个字节,而 Double 是 8 个字节,即每个元素 16 个字节,因此大约 40 兆字节。我不明白为什么我有这个问题。我倾向于在添加新元素之前从字典中删除元素。
    • @Anish:嗯,你还没有说你正在使用IEnumerable<T> 的什么实现。例如,如果您使用LinkedList,那么每个元素都会有相当大的开销。即便如此,我也不认为 250 万个 KVP 会成为问题。是什么让您相信是这个缓存导致了问题?
    【解决方案3】:

    既然你问为什么 GC 不救你,我会给出答案。

    使用带有垃圾收集器的编程语言/环境让您的生活更轻松,但不会让内存管理成为过去。

    如果您在 32 位 xp 机器上分配超过 2 gig 的大块内存,您就达到了第一个 .Net 内存边界。在内存中保留 2 gig 总是一个坏主意。

    在运行大型数据库或类似数据库的内存受限机器上,您将很快达到可用内存的边界。由于 GC 不知道操作系统,它可能不会及时注意到内存不足的情况(创建像位图这样的大对象可能会触发这种情况)。一旦你将一个巨大的对象设置为无用,手动调用 GC.Collect 在这里会有很大帮助。

    在内存中保存一个大字典是一个非常简单的描述。你能告诉我们收藏中有什么吗?理论上这些物品有多大。

    如果您的意思是像 2,147,483,647 项这样大的项目,您可能已经达到整数大小限制。

    总结一下:

    • 不要将不需要的项目保留在内存中或将它们换出到磁盘。
    • 释放“大”项目后,请调用 GC.Collect(但不要在删除项目的循环中,请在循环之后)

    【讨论】:

    • 哦,用性能计数器测量你的应用程序使用了多少内存,这会告诉你发生了什么。
    【解决方案4】:

    我不确定,如果我错了,请告诉我,但也许字典在大于 85kB 时存储在大对象堆中(如字节 [90000])

    就像加布说的:

    我可以看到大对象堆可能会变得碎片化,并且您将无法在某个点之后增长字典

    当 LOH 碎片化时,有时它没有足够的空间来存储具有连续地址的对象。这就是导致 OutOfMemory 异常的原因。它更像是 LOH 异常中的 Out Of Contigus 空间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2018-10-04
      • 1970-01-01
      相关资源
      最近更新 更多