【问题标题】:c# multithreading mem usage - App slowing down and CPU usage dropsc# 多线程内存使用 - 应用程序变慢和 CPU 使用率下降
【发布时间】:2010-09-11 00:19:01
【问题描述】:

我有一个多线程应用程序,它可以操作内存中的数据(没有数据库或网络访问权限)。我在两台机器上试过这个,一台是Xeon双四核CPU,另一台是双拨号核。生成了 5 个线程。

然后这个多线程进程启动它运行得非常快,5 核 CPU 使用率为 60%,物理内存为 RAM 容量的 50%。 (来自任务管理器的信息)。在大约 1/3 之后,它开始变慢,CPU 利用率下降到略低于 20%。到 2/3 秒时,速度太慢了,完成后三分之一需要 1 天,而前 1/3 需要半小时。

该进程创建了许多SortedLists和Lists,所以我开始怀疑垃圾收集器无法应对,虽然任务管理器内存使用情况还不错......我想尝试强制GC释放立即未使用的集合,这是合理的甚至可行的吗?为什么 CPU 利用率会下降?

【问题讨论】:

    标签: c# multithreading performance cpu-usage garbage-collection


    【解决方案1】:

    强制垃圾收集器运行几乎总是一个坏主意。 (在某些情况下,强制它提前运行实际上可以提高对象的生命周期)

    下载MemprofilerAntsdotTrace 之类的工具(它们都有试用版),以确定您是否存在内存泄漏。您是否分配了大于 85Kb 的对象?

    另外,您使用的是什么版本的操作系统和 .NET Framework? (服务器版和 PC 版 GC 的工作方式存在差异)

    另外,请注意插入 SortedList 是 O(N)(而 SortedDictionary 插入是 O(logN):

    SortedList 泛型类是一个 O(log n) 的二叉搜索树 检索,其中 n 是 字典中的元素。在这, 它类似于 SortedDictionary 泛型类。这两个班有 相似的对象模型,并且都有 O(log n) 检索。两人在哪里 类的不同在于内存使用和 插拔速度:

    • SortedList 使用的内存少于 排序字典。

    • SortedDictionary 的插入速度更快 和未排序的删除操作 数据,O(log n) 而不是 O(n) 排序列表。

    • 如果列表被一次性填充 从排序数据来看,SortedList 更快 比排序字典。

    Ref.

    您如何管理对这些列表的多线程访问?你能发布一些精简的代码吗?

    【讨论】:

    • 我使用的是 XP Professional SP2,据我所知,.NET 3.5 与 2.0 核心相同。我正在构建的列表很长,但它们包含整数和双精度数。我敢肯定,列表本身大于 85K。
    • 是的,这是正确的方向。我需要下载一个分析器并弄清楚如何使用它,否则它只是在黑暗中闲逛。
    • @Misha:你是对的 - 不要在黑暗中戳。另一方面,分析器可能没有太大帮助。我使用的方法是 stackshots (stackoverflow.com/questions/375913/…)。如果问题是锁争用,您会立即发现。
    【解决方案2】:

    我猜想将大量项目添加到负载很重的集合中并没有达到应有的性能。我注意到与旧 SQL 查询类似的情况 - 记录集中的 100 条记录很快,但 50 万条记录会以指数方式减慢速度。

    要检查 GC,请运行 perfmon 并查看(或记录)垃圾收集器和内存分配的性能计数器。

    【讨论】:

    • 这对于许多场景都是正确的,但这里列表的大小不会在迭代中增加 - 它每次都会被丢弃和重建,所以它的长度不会增加......我需要看看进入性能
    • 实际上,我在撒谎 - 有一个跨线程使用的结果列表,但它只有 thosand 长,所以我不认为这是问题。
    • @Misha:如果所有线程都试图经常访问它,它可能是。
    • 性能监视器 +1。为 perfmon 添加一个计数器以检查您的进程在 GC 中花费的时间百分比。
    【解决方案3】:

    听起来像是数据结构锁定问题。不知道自己在做什么很难说。

    尝试使用无锁非连续集合之一,例如 ConcurrentDictionaryConcurrentBag 和/或适当的队列,例如 BlockingCollection

    【讨论】:

      【解决方案4】:

      您很可能将所有物理内存都用于您的数据,然后 Windows 开始使用虚拟内存,这要慢得多。您应该尝试使用内存分析器来查看哪个对象占用了您的所有内存,并考虑定期处理其中一些对象,以免耗尽您的所有 RAM。

      【讨论】:

        【解决方案5】:

        5 个线程的 5 个内核上的 60% CPU。我假设 each 核心占 60%。这实际上是非常糟糕的。您不能单独将 CPU 驱动到 100% 进行内存操作(没有数据库、没有网络、没有文件 IO),这意味着您对锁定的争用非常大。随着程序的进行,您的结构可能会增长(某些列表/字典中的元素更多),您持有锁的时间更长,结果是更少的 CPU 甚至更慢的性能。

        如果没有任何真实的性能数据,很难判断,但这看起来与 GC 无关。它看起来更像是数据结构中的高竞争。您应该在分析器下跟踪您的应用程序,并查看 CPU/等待时间花费最多的地方。有关采样分析器的快速介绍,请参阅 Pinpoint a performance issue using hotpath in Visual Studio 2008

        【讨论】:

        • 莱姆斯,这很有帮助。 VS2008 看不到调用树视图?需要先从MS下载吗?
        • 我认为只有在 VSTS 2008 和 Ultimate 和 Premium 2010 中。标准 2008/2010 没有它。 msdn.microsoft.com/en-us/library/ms182372.aspx
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-10
        • 1970-01-01
        相关资源
        最近更新 更多