C#过多的垃圾收集 - 大字符串,G2压力?

时间:2015-07-13 17:51:29

标签: c# garbage-collection large-object-heap

我正在使用64位IIS在Win 2k8(.NET 4.5)上运行的C#中编写一个高容量卷Web服务,它可以处理XML有效负载并对小型和大型对象(大型对象)执行各种操作对象主要是字符串,有些超过85k(所以进入LOH))。请求是无状态的,内存使用量随着时间的推移保持稳定。每个请求正在分配和释放大量内存,似乎没有内存泄露。

每秒最多运行25笔交易,平均通话时间为5秒,根据两个分析工具,它在GC中花费了40-60%的时间,而perfmon在5秒内显示了20 G0和G1的稳定收集,以及5秒内的15个G2集合 - 这意味着很多(我们认为)过早地向G2提出我们期望保留在G0中的数据。我读到的一切都表明这是非常过分的。我们希望系统能够以高于25 tps的吞吐量执行,并假设GC活动阻止了这一点。

为请求提供服务的机器有大量内存--16GB - 负载下的应用程序在负载下一小时消耗最多1GB。我知道更大的堆不一定会让事情变得更好,但是有多余的内存。

我很欣赏这些具体细节(如果时间允许的话,会尝试用简单的应用程序重新创建条件) - 但有人可以解释为什么我们会看到如此多的G2 GC活动吗?我应该关注LOH吗?人们一直告诉我CLR的GC“适应”你的负载,但在这种情况下并没有改变它的行为,并且与其他运行时不同,我似乎很少能够调整它(尝试过工作站GC,但是有很少有可观察到的差异)。

2 个答案:

答案 0 :(得分:0)

Microsoft决定设计String类,以便所有字符串都作为单个字符序列存储在内存中。虽然这适用于某些使用模式,但它对其他人来说非常有用。

我发现非常有用的一件事是尽可能避免创建String的实例。如果一个方法通常用于对提供的字符串的一部分进行操作,并且反过来要求其他方法对其中的一部分进行操作,那么这些方法应该接受指定它们应该操作的Subst范围的参数。 。这将避免第一种方法的调用者需要使用String为方法构建新的Subst,并且将避免需要将方法调用String将字符串的一部分馈送给其呼叫者。在我使用这种技术的某些情况下,创建数千个make MACHINE=kvm_x86_64 all个实例 - 有些非常大 - 可以用替换。

答案 1 :(得分:0)

  

CLR的GC"适应"你的负担

它无法知道您愿意承受多少内存作为开销。在这里,您可能希望为应用程序提供5GB的堆,以便集合更少见。 GC没有内置的调音旋钮(主观说明:这是一个很小的)。

您可以在短时间内使用其中一种低延迟模式强制更大的堆大小。这应该导致GC努力避免G2收集。当消耗量达到5GB时,监控RAM使用情况并禁用低延迟模式。

这是一个冒险的策略,但我认为你能做的最好。

我不会这样做。您最大可以获得2倍的吞吐量。你的CPU是最大的,对吧? Workstation GC不会扩展到多个核心并使CPU未使用。