C#多线程内存使用-应用程序变慢且CPU使用率下降

3
我有一个多线程的应用程序,操作内存中的数据(没有数据库或网络访问)。我在两台机器上尝试过,一台是Xeon双四核CPU,另一台是双双核。生成了5个线程。
然后这个多线程进程启动后非常快,并且CPU使用率为5个核心的60%,物理内存为RAM容量的50%(来自任务管理器)。当它完成1/3时,它开始变慢,CPU利用率降至略低于20%。当它到达2/3时,它变得非常缓慢,最后1/3需要1天才能完成,而第一1/3只需半小时。
该进程创建了许多SortedList和List,因此我开始怀疑垃圾回收器无法处理,尽管任务管理器内存使用情况并不那么糟糕... 我想尝试强制GC立即释放未使用的集合,这是合理的或可行的吗?为什么CPU利用率会下降?
5个回答

1
强制垃圾回收几乎总是一个坏主意。(在某些情况下,提前运行它实际上可能会促进对象的生命周期。)
下载像MemprofilerAntsdotTrace这样的工具(它们都有试用版),以确定是否存在内存泄漏。你是否分配了大于85Kb的对象?
此外,你使用的操作系统和.NET Framework版本是什么?(服务器和个人计算机版本的GC工作方式有所不同)
还要注意,将元素插入SortedList的时间复杂度为O(N)(而将元素插入SortedDictionary的时间复杂度为O(logN))。
SortedList 泛型类是一棵二叉搜索树,具有 O(log n) 的检索速度,其中 n 是字典中元素的数量。在这方面,它与 SortedDictionary 泛型类类似。两个类具有相似的对象模型,并且都具有 O(log n) 的检索速度。这两个类的区别在于内存使用和插入/删除速度:
  • SortedList 比 SortedDictionary 使用更少的内存。
  • SortedDictionary 对于未排序数据具有更快的插入和删除操作,为 O(log n),而 SortedList 为 O(n)。
  • 如果列表一次性从排序数据中填充,则 SortedList 比 SortedDictionary 更快。
Ref.
你如何管理对这些列表的多线程访问?能否发布一些简化后的代码?

我正在使用带有.NET 3.5的XP专业版SP2,据我所知,它与2.0核心相同。我正在构建的列表很长,但它们包含整数和双精度浮点数。我确定这些列表本身比85K还要大。 - Misha
是的,这是正确的方向。我需要下载一个分析器并弄清如何使用它,否则就像在黑暗中摸索一样。 - Misha
@Misha:你说得对-不要在黑暗中摸索。另一方面,探查器可能没有太大帮助。我使用的方法是堆栈快照(https://dev59.com/n3RC5IYBdhLWcg3wOOL1#378024)。如果问题是锁竞争,你会马上发现。 - Mike Dunlavey

1

我猜向一个已经很重的集合中添加大量项并不像它本应该的那样高效。我曾经在一个旧的 SQL 查询中注意到了类似的情况——100 条记录的记录集是快速的,但是半百万条记录会使事情呈指数级放缓。

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


这在许多情况下都是正确的,但在这里,列表的大小不会随着迭代而增加 - 它在每次迭代中被丢弃并重新构建,因此其长度不会增加... 我需要查看 perfmon。 - Misha
实际上,我在撒谎 - 有一个结果列表在线程之间使用,但它只有一千个项目,所以我不认为这是问题所在。 - Misha
@Misha:如果所有线程都经常尝试访问它,那么可能会出现这种情况。 - Mitch Wheat
在perfmon中加入一个计数器,以检查您的进程在GC中花费的时间百分比。+1 for perfmon. - JulianR

1

听起来像是数据结构锁定问题。如果不知道你具体在做什么,很难说。

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


0

很可能您正在使用所有物理内存来存储数据,当内存不足时,Windows会开始使用虚拟内存,这会导致速度变慢。您应该尝试使用内存分析器查看哪些对象占用了大量内存,并考虑定期处理其中一些对象以避免使用完所有RAM。


0

从5个线程中的5个核心占用60%的CPU。我认为这是每个核心都占用60%。这实际上非常糟糕。您不能仅通过内存操作将CPU推到100%(没有数据库,没有网络,没有文件IO),这意味着锁定争用非常大。随着程序的进行,您的结构体大小可能会增加(某些列表/字典中的更多元素),您需要持有更长时间的锁定,结果是更少的CPU和更慢的性能。

很难在没有任何真实性能数据的情况下判断,但这似乎与GC无关。它看起来更像是数据结构中高争用。您应该在分析器下跟踪应用程序,并查看CPU /等待时间花费最多的地方。请参阅 在Visual Studio 2008中使用hotpath针对性能问题进行快速介绍 以了解采样分析器的简介。


Remus,这非常有帮助。我在VS2008中找不到“调用树视图”?我需要先从微软下载它吗? - Misha
我认为这只存在于VSTS 2008、Ultimate和Premium 2010中。Standard 2008/2010没有它。http://msdn.microsoft.com/en-us/library/ms182372.aspx - Remus Rusanu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接