2011-04-10 71 views
2

我们的多线程应用程序做了冗长的计算循环。平均来说,它需要大约29秒才能完成一个完整周期。在那段时间内,.NET性能计数器% time in GC占到8.5%。它全部由Gen 2系列产品组成。什么会导致性能改进?时间GC,汇集

为了提高性能,我们实现了我们的大对象池。我们实现了100%的娱乐率。整个周期现在平均只需要20秒。 GC中的%时间显示0.3 ... 0.5%之间。现在,GC只执行Gen 0集合。

让我们假设,该池是有效地实现,而忽略附加花费的时间执行。比我们的表现改善了大约33%。这与以前的8.5%的GC值有什么关系?

我有一些假设,我希望可以确认,调整和修订:

1)(如果我没有看错),并测量2次的关系“在GC时间”跨越:

  • 2个GC周期和用于最后一个完整GC周期
  • 时间之间的时间,该值被包括在第一范围。什么是不包括在第二时间跨度

,将停止和重新启动工作线程阻塞GC的开销。但是,这怎么可能达到整个执行时间的20%呢?

2)通常阻断线程GC可以胎面之间引入争用?这只是一个想法。我无法通过VS并发分析器来确认。

3)与此相反,它可以确认页面未命中(数性能计数器:内存 - 页面错误秒)> /为比用于与应用的UNPOOLED应用(25.000每秒)显著更高低GC率(每秒200次)。我可以想象,这也会带来很大的改善。但是,什么可以解释这种行为?难道是因为频繁的分配会导致虚拟内存地址空间中的一个更大的区域被使用,因此难以保存到物理内存中?那么如何衡量这个原因呢?

BTW:GCSettings.IsServerGC =假,.NET 4.0,64位,Win7上,4GB,英特尔酷睿i5运行。 (很遗憾的大问题..;)

+2

我很犹豫回答你的问题,因为缺少很多信息给你一个真正的答案。 无论如何 - 总体性能改进*可能是由于: 1.减少GC时间(计算为〜8.0%=〜2秒)2.您所有的时间不必重新创建那些真正大的物体,因为它们现在已经有效地汇集了。这可能会非常昂贵,而且如果您将8.5%的时间花费在GC上,可能会非常昂贵。 – NightDweller 2011-04-10 16:51:09

+0

@NightDweller感谢您的评论。这些对象是'唯一'的大数组。汇集它们所节省的唯一时间是最初清除它们所需的时间(将其元素设置为0)。另一方面,我认为在任何托管堆分配中,预计成本更高。 – user492238 2011-04-10 17:04:23

+1

在某些情况下分配可能会很昂贵 - 如果您经常重新分配,并且需要长时间连续的内存块,这些内存块可能会因为碎片而变得很少。但是我必须承认它似乎并不全是可能的。 您是否尝试在代码上运行一个分析器? (之前/之后),应该给你一个非常明确的答案,以改善... – NightDweller 2011-04-10 21:40:16

回答

2

预分配的对象,来改善并发线程不再有进入全球锁保护的垃圾回收堆中分配的对象。该锁保持很短的时间,但显然你分配了很多对象,所以线程不会锁定锁。

性能计数器“关于在GC时间”措施的CPU时间百分比花在收集,而不是执行常规代码。如果有很多gen#2集合,并且分配对象的速度非常快,以至于后台收集无法继续并且线程必须被阻止,则可以获得大数目。拥有更多线程会使情况变得更糟,您可以分配更多。

+0

请注意,全局分配锁不用于所有虚拟机。我记得新的Mono GC为每个线程分配了不同的部分。 – Dykam 2011-04-10 18:12:12

+0

gcserver版本也是如此。 – 2011-04-10 18:24:40

3

然后我们得到了约33%的绩效改进 。那怎么 涉及到为 8.5%GC前值?

通过合并,您还可以节省花费在new上的时间,这可能相当可观,但我不会花时间来平衡数字。

而不是“在马上看礼物马”,为什么不继续寻找其他“瓶颈”?

当您删除一个性能问题时,由于分母较小,因此您可以让其他人占用较大的时间百分比。 所以他们更容易找到,只要你知道如何寻找他们

Here's an example, and a method. 您清除了一个大问题。 这使得下一个百分比更大,所以你清理一个。 冲洗并重复。 它可能需要花费很少的时间,以至于需要在它周围包裹一个临时外部循环,只是为了使其花费足够长的时间来进行调查。 你继续这样走下去,逐渐让这个程序花费越来越少的时间,直到你达到收益递减。

这就是如何使代码快速。

+0

谢谢,感谢您的反馈。但是这错过了这个问题?我并不关心任何*特定应用程序的性能,而是希望更深入地了解导致性能改进的根本原因。通过学习,我可以在将来节省更多时间,立即防止这些瓶颈(我现在甚至没有想到它们存在)。 – user492238 2011-04-11 03:57:13

+0

@ user492238:正如我所说的,当您使用池回收使用的对象时,不仅可以节省GC时间,还可以节省“新”时间。我经常看到程序花费大量时间1)分配内存并运行初始化程序,或者2)运行析构程序。这就是你在储存时保存的内容。 *然而,*无论你和我在避免缓慢方面有多好,*它都会发生*。因此,学习如何找到它更为重要,以便在发生之后以及之前将其删除。 – 2011-04-11 12:08:34

相关问题