大对象堆友好IDictionary

时间:2011-05-05 04:26:28

标签: c# large-object-heap

我们有一个应用程序可以在多个Dictionary中保存大量对象,其中一些在应用程序的生命周期中不断增长(交易应用程序包含大量工具和不断增长的订单/交易)。

由于大对象堆碎片,我们遇到了OutOfMemoryException的问题。

为了解决这个问题,我试图写一个'大'字典,它实现为一个两级字典,其中所有的叶子字典都不够大,不能在LOH上分配。我使用了一致的哈希算法,以避免在单个存储桶变得太大时重新整理整个字典。一致的哈希'circle'是来自C5集合库的TreeDictionary

我的问题是,C#有没有更好的数据结构(或者我描述的更好的实现)?

更新

这是“大型”字典的实现:https://gist.github.com/956621

据我所知,它不是万无一失的,因为LOH堆阈值都不在规范中,也不是每个Dictionary条目或缩放算法的大小。然而,这是目前我能想到的最好的,以避免应用程序在中午爆炸。

2 个答案:

答案 0 :(得分:3)

当字典是应用程序中最大的数据结构时,它是一种不幸的数据结构。当散列表变得太满时,散列表的大小通常会加倍,并且在调整大小期间需要150%的重定位,正好在关键时刻。哈希表在巨大的时候运行得非常好,但它需要连续分配,这会强调堆算法。

您可以使用多级哈希表减少这些缺点,例如使用哈希码的一个字节作为256个哈希表的索引。这肯定会增加一些开销,但更重要的是,这个和其他策略通过摆弄随机性(例如你获得的哈希码并且可能使事情变得更糟,性能更差)而充满了危险。使用这种方法需要良好的理论基础和扎实的实证检验。但它可以工作。

另一种策略是为最坏的情况预先分配最大的数据结构并尽早分配。没有必要进行细粒度分配,但现在你面临灾难性失败的幽灵,如果它应该用完了。这是一个选择。

答案 1 :(得分:1)

我认为这要求改变算法。

从我所听到和理解的情况来看,GC非常擅长打包和碎片整理内存。因此,您的问题源于简单的事实,即您将太多数据保存到内存中。

你在内存中保留了多少数据?

您是否考虑过使用数据库?紧凑的可能就够了。

或者只是告诉您的客户,要正确运行您的应用,他需要16 GB的内存。如果你的应用程序需要所有16 GB的内存,那么肯定有问题。

修改: 从不同的角度看你的问题并在阅读你的编辑后我得到了一个问题:你的对象有多大?或者它们包含长列表或数组?您多久删除一次这些对象?

我认为问题可能不在字典本身,而是太大而且经常删除/添加的对象。也许使用某种捕捉或游泳池可能是有利可图的。如果您使用列表,则使用prealocated创建这些列表。

也许使用可变结构而不是可变类可以减轻碎片。