我有一个多线程应用程序来操作内存数据(没有数据库或网络访问)。我在2台机器上试过这个,一台机器是Xeon双四核CPU,另一台是双拨盘核心。产生了5个线程。
然后这个多线程进程启动它运行得非常快,5个内核的CPU使用率为60%,物理内存占RAM容量的50%。 (来自任务经理的信息)。在大约1/3之后它开始减速并且CPU利用率下降到略低于20%。当它达到2/3的速度时,它需要1天才能完成最后的三分之一,而前半部分需要半个小时来完成前1/3。
该过程创建了许多SortedLists和Lists,所以我开始怀疑垃圾收集器无法应对,尽管任务管理器的内存使用情况并不是那么糟糕...我想尝试强制GC释放立即使用未使用的集合,这是合理的甚至是可行的吗?为什么CPU使用率会下降?
答案 0 :(得分:1)
强制垃圾收集器运行几乎总是一个坏主意。 (在某些情况下,强制它提前运行实际上可以促进对象的生命周期)
下载Memprofiler,Ants或dotTrace等工具(它们都有试用版),以确定您是否泄漏了内存。你在分配大于85Kb的物体吗?
此外,您使用的是哪个版本的操作系统和.NET Framework? (GC的服务器和PC版本的工作方式有所不同)
另外,请注意,插入SortedList是O(N)(而SortedDictionary插入是O(logN):
SortedList泛型类是一个 二进制搜索树,带O(log n) 检索,其中n是数字 字典中的元素。在这, 它类似于SortedDictionary 泛类。这两个班有 类似的对象模型,都有 O(log n)检索。哪两个 类别不同在于内存使用和 插入和移除速度:
SortedList使用的内存少于 SortedDictionary。
SortedDictionary的插入速度更快 和未分类的删除操作 数据,O(log n)而不是O(n) 排序列表。
如果列表一次全部填充 从排序数据中,SortedList更快 而不是SortedDictionary。
您如何管理这些列表的多线程访问?你能发一些简短的代码吗?
答案 1 :(得分:1)
我想将大量项目添加到负载很重的集合中并不是因为它可能是高效的。我注意到类似于旧的SQL查询 - 记录集中的100条记录很快,但是有50万条记录以指数方式减慢了速度。
要检查GC,请运行perfmon并查看(或记录)垃圾收集器和内存分配的性能计数器。
答案 2 :(得分:1)
听起来像数据结构锁定问题。如果不确切知道自己在做什么,就很难说。
尝试使用其中一个无锁的非连续集合,例如ConcurrentDictionary
或ConcurrentBag
和/或BlockingCollection
等适当的队列。
答案 3 :(得分:0)
您很可能将所有物理内存与数据一起使用,Windows之后开始使用虚拟内存,速度要慢得多。您应该尝试使用memmory探查器来查看哪个对象占用了您的所有内存,并考虑定期处理其中一些目标,以防止耗尽所有内存。
答案 4 :(得分:0)
5个线程的5个核心上60%的CPU。我假设每个核心上有60%。这实际上非常糟糕。你无法将CPU驱动到100%单独进行内存操作(没有数据库,没有网络,没有文件IO),这意味着你对锁定的争用很大。随着程序的进展,你的结构可能会增加大小(某些列表/字典中的元素越多),你持有更长时间的锁,结果是CPU更少,性能更低。
很难说没有任何真实的性能数据,但这看起来与GC无关。它看起来更像是数据结构中的高争用。您应该在Profiler下跟踪您的应用程序,并查看CPU /等待时间最多的位置。有关采样分析器的快速介绍,请参见Pinpoint a performance issue using hotpath in Visual Studio 2008。