【问题标题】:Keep a large number of objects in memory for a long time将大量对象长期保存在内存中
【发布时间】:2009-02-19 12:50:12
【问题描述】:

在我的 ASP.NET 应用程序中,我有一个包含大量对象的字典(假设有 1M 大,以后可能会更大),存储在字典中的对象是引用类型而不是结构类型,该字典旨在用作此类对象的缓存(我有理由不使用 ASP.NET 缓存来缓存此类对象,但我将其用于缓存其他内容)。

这会导致 GC 出现问题吗?我一直听说长寿对象会影响 GC 的性能并导致它在收集过程中花费更多时间,有没有办法避免这种情况?据我了解,字典(和对象)应该最终出现在 Gen2 中,除非系统内存不足,否则 GC 不会收集(如果我错了请纠正我),那么如果系统有很多怎么办内存,GC仍然会以相同的频率收集Gen2吗?肯定还有其他应用会长期缓存大量数据,不知道他们是如何避免GC的问题的。

非常感谢任何建议...

【问题讨论】:

    标签: .net asp.net performance garbage-collection


    【解决方案1】:

    在大约 1M 条目时,底层数组的字典将不可避免地最终出现在 LOH 中。鉴于此,将其预先分配到与其最终包含的条目数量相称的大小可能是一个好主意(这可能会严重适得其反,并且在测试模式下可能会很痛苦)。

    字典中的对象应该提供一个非常好的哈希码实现。这与内存使用直接无关,只是查找效率。然而,如果你用更高的负载因子换取更少的内存,使用错误的哈希最终可能会降低字典的行为,它不再是 O(1)。

    它包含的长寿项目应该是:

    1. (最佳情况)不包含引用类型的实例字段。

      • 然后 GC 无需遍历数组中的每个对象(GC 实现可能不会执行此优化,因此您的里程可能会有所不同)。
    2. 确保您的应用程序不会陷入Mid Life Crisis 风格的行为

      • 触发更多您希望避免的 gen2 集合。
    3. 它们包含的任何引用都不应指向 Gen0 或 Gen1 堆

      • 这会导致大量写入障碍,从而减慢您的第 0 代/第 1 代收集速度。

    由于您声明这是一个缓存,但没有提及您的保留政策,我认为这个 advice 也值得一提。

    您正在缓存的对象类型的一些迹象可能是相关的 4/8MB 或者即使使用现代处理器缓存,连续内存也非常多,因此对缓存的频繁请求可能比更紧凑、更小的缓存具有更差的性能。更好的保留政策。

    【讨论】:

      【解决方案2】:

      您对场景的理解是正确的,只要系统不渴望内存 第 2 代收集应该是不频繁的,因此在其中保留许多长期存在的对象应该没有问题。

      如果您必须仔细编码以避免 GC 出现“问题”,那么 GC 就不会很好地完成它的工作。

      真正需要关注的唯一领域是大型分配(单个分配 > 86KB)有很多这些即将到来可能是一个问题。

      【讨论】:

        【解决方案3】:

        我不能确定它是否明智,但是如果您不希望它被收集,请使用以下代码:

        GC.KeepAlive(object);
        

        【讨论】:

        • 老兄,这不是他们要的。还有为什么 KeepAlive 是不明智的?它有它的位置和它的用途。
        • 感谢您的回答,但正如我在 GC.KeepAlive() 的文档中看到的那样,它只应在您没有对对象的引用并且对象正在用于非托管代码中的情况下使用(还有其他情况,但它们也不适用于我的情况)..
        • 好吧好吧,伙计们,只是想帮忙。
        【解决方案4】:

        您需要注意项目不会最终进入大对象堆 (>85K)。如果它们保持常驻,这不是问题,但如果数据被换入和换出,由于 LOH 未压缩,您最终可能会出现内存碎片。

        【讨论】:

        • 字典中的项远小于85k,但是字典对象本身呢?它肯定会大于 85k,它会以 LOH 结尾吗?
        猜你喜欢
        • 1970-01-01
        • 2011-02-22
        • 1970-01-01
        • 2018-01-31
        • 2013-02-22
        • 2016-10-16
        • 2010-11-03
        • 1970-01-01
        • 2015-09-09
        相关资源
        最近更新 更多