10

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

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

为了解决这个问题,我尝试编写一个“大”字典,它被实现为一个两级字典,其中所有叶字典都不够大,无法在 LOH 上分配。我使用了一致的散列算法来避免当单个存储桶变得太大时必须重新散列整个字典。一致的散列“圆圈”TreeDictionary来自 C5 集合库。

我的问题是,对于 C# 是否有更好的数据结构(或者可能是我所描述的更好的实现)?

更新

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

我知道这不是万无一失的,因为规范中既没有 LOH 堆阈值,也没有每个 Dictionary 条目的大小或缩放算法。但是,这是目前我能想到的最好的方法,以避免应用程序在中午崩溃。

4

2 回答 2

3

当字典是应用程序中最大的数据结构时,它是一种不幸的数据结构。当哈希表变得太满时,它的大小通常会翻倍,这需要在调整大小期间(在关键时刻)进行 150% 的过度分配。哈希表在巨大时工作得非常好,但它需要连续分配,这会强调堆算法。

您可以使用多级哈希表来减少这些缺点,例如使用哈希码的一个字节作为 256 个哈希表的索引。这肯定会增加一些开销,但更重要的是,这种策略和其他策略充满了危险,因为它会摆弄诸如您获得的哈希码之类的随机性,并可能使性能变得更糟。使用这种方法需要良好的理论基础和扎实的经验测试。但它可以工作。

另一种策略是为最坏的情况预先分配最大的数据结构并尽早分配。不需要细粒度的分配,但现在如果它用完,您将面临灾难性故障的幽灵。这是一个选择。

于 2011-05-05T05:15:25.340 回答
1

我认为这需要改变算法。

据我所知,GC在内存打包和碎片整理方面做得相当不错。因此,您的问题源于一个简单的事实,即您将太多数据保存到内存中。

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

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

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

编辑:从不同的角度看待您的问题,在阅读您的编辑后,我得到了问题:您的对象有多大?或者它们是否包含长列表或数组?您多久删除/添加这些对象?

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

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

于 2011-05-05T04:58:45.587 回答