2010-05-26 101 views
4

继续从Understanding VS2010 C# parallel profiling results,但更重要的是讨论:每线程内存管理在C#

我有很多,在并行工作线程(使用的Parallel.For /每次),它使用许多内存分配小班。

这会在全局内存分配器线程上产生争用。

有没有办法指示.NET为每个线程预分配一个内存池,并从该池中进行所有分配?

目前我的解决办法是我自己的实现内存池(T型,这是在线程之间循环的对象的全局分配阵列),帮助了很多,但效率不高,因为:

  1. 我可以” t指示.NET从特定的内存片分配。
  2. 我仍然需要多次拨打新的来分配池的内存。

谢谢,

+0

是否有可能使T成为值类型并将其分配到堆栈而不是堆中? – 2010-05-26 13:58:03

+1

这里有什么问题。你的程序运行缓慢吗?内存不足,即。崩溃?只是使用大量的内存? – 2010-05-26 14:02:09

+0

@tehMich:我不这么认为。这些对象是复合类,将它们分解为单独的变量或数组将会很麻烦。此外,他们需要大量,我不知道会适合堆栈(我说的是数十兆字节)。 – Haggai 2010-05-26 15:03:39

回答

15

我搜索了两天,试图找到你遇到的同一问题的答案。答案是你需要将垃圾收集模式设置为服务器模式。默认情况下,垃圾收集模式设置为工作站模式。 将垃圾收集设置为服务器模式会导致托管堆分裂为单独管理的部分,每个CPU一个部分。 要做到这一点,你需要添加一个配置设置到你的app.config文件。

<runtime> 
    <gcServer enabled="true"/> 
</runtime> 

我的12核Opteron 6172的速度差异很大!

+0

现在,这是新闻,从来不知道你可以这样调整GC。我会在自己的代码中给出一个镜头,非常感兴趣,看看它会做什么! – gjvdkamp 2011-06-06 12:15:38

0

垃圾收集器不分配存储器。

听起来更像是你分配了很多小的临时对象和一些长寿命的对象,垃圾回收器花费了大量的时间垃圾收集临时对象,所以你的应用程序不需要请求更多的操作系统内存。从.NET Framework 4 Advanced Development - Garbage Collection

只要地址空间是在托管堆中可用,运行时继续为新对象分配空间。但是,记忆不是无限的。最终垃圾收集器必须执行一个收集以释放一些内存。

解决方案:不要分配大量的小临时对象。Garbage Collection and Performance上的页面也可能有帮助。

+0

我的应用程序的内存需求确实很大(几千兆字节),但我有一个8GB内存和GC采集会话只发生一次,每分钟左右,并且非常短 – Haggai 2010-05-26 15:23:39

+0

“GC采集会话每分钟只发生一次,而且非常短“似乎与”大部分同步时间花费在等待GC线程完成内存分配上“相矛盾。 – 2010-05-31 15:26:07

0

您可以预先分配一堆对象,并将它们保存在用于单独线程的组中。但是,您很可能无法从中获得更好的表现。

垃圾收集器专门设计用于高效地处理小型短暂对象。如果将对象保存在一个池中,它们会很长寿,并且会在垃圾回收过程中存活下来,这意味着它们将被复制到第二代堆中。这种复制将比分配新对象更加昂贵。

+0

你的第一段完全是我目前的解决方案。当我在许多线程中多次重复使用这些对象时,我相信在这种情况下复制到第二代堆是无足轻重的。 我该如何检查它是否是? – Haggai 2010-05-26 15:09:17