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

C#垃圾收集过多-大字符串,G2压力?,c#,garbage-collection,large-object-heap,C#,Garbage Collection,Large Object Heap,我正在用C#编写一个高容量的web服务,运行在Win 2k8(.NET 4.5)上的64位IIS中,该服务使用XML有效负载,并对大小对象执行各种操作(其中大对象主要是字符串,一些超过85k(因此进入LOH))。请求是无状态的,随着时间的推移,内存使用保持稳定。每个请求分配和释放了大量内存,没有内存泄漏 每秒最多运行25个事务,平均呼叫持续5s,根据两个分析工具,它在GC中花费了40-60%的时间,perfmon在5秒内显示稳定的20个G0和G1收集,在5秒内显示15个G2收集,这意味着大量(我

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

每秒最多运行25个事务,平均呼叫持续5s,根据两个分析工具,它在GC中花费了40-60%的时间,perfmon在5秒内显示稳定的20个G0和G1收集,在5秒内显示15个G2收集,这意味着大量(我们认为)对于我们希望停留在G0的数据,提前向G2提出建议。我所读到的一切都表明这是非常过分的。我们期望系统能够以高于25 tps的吞吐量执行,并假设GC活动正在阻止这一点

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


我理解这是对细节的轻描淡写(如果时间允许,将尝试用一个简单的应用程序重新创建条件),但是有人能解释为什么我们看到这么多G2 GC活动吗?我应该关注LOH吗?人们一直告诉我CLR的GC“适应”您的负载,但在这种情况下它不会改变它的行为,而且,与其他运行时不同,我似乎无法对其进行调优(已经尝试过工作站GC,但观察到的差异非常小).微软决定设计
字符串
类,以便将所有字符串作为单一字符序列存储在内存中。虽然这对某些使用模式很有效,但对其他使用模式却非常有效


我发现一件非常有用的事情是尽可能避免创建
String
的实例。如果一个方法经常被用于对所提供字符串的一部分进行操作,并且反过来又会要求其他方法对它的一部分进行操作,那么这些方法应该接受指定它们应该操作的
字符串的范围的参数。这将避免第一个方法的调用者需要使用
Subst
来构造一个新的
String
以供方法执行操作,并且将避免需要方法调用
Subst
将字符串的一部分提供给调用者。在我使用这种技术的某些情况下,创建数千个
String
实例(有些相当大)可以用零代替。

微软决定设计
String
类,以便所有字符串都作为单一字符序列存储在内存中。虽然这对某些使用模式很有效,但对其他使用模式却非常有效

我发现一件非常有用的事情是尽可能避免创建
String
的实例。如果一个方法经常被用于对所提供字符串的一部分进行操作,并且反过来又会要求其他方法对它的一部分进行操作,那么这些方法应该接受指定它们应该操作的
字符串的范围的参数。这将避免第一个方法的调用者需要使用
Subst
来构造一个新的
String
以供方法执行操作,并且将避免需要方法调用
Subst
将字符串的一部分提供给调用者。在我使用这种技术的某些情况下,创建数千个
String
实例(有些相当大)可以用零替换

CLR的GC“适应”您的负载

它不知道你愿意容忍多少内存作为开销。在这里,您可能希望给应用程序提供5GB的堆,这样集合就少多了。GC没有内置的调优旋钮(主观上的注释:这是一个小问题)

通过在短时间内使用一种低延迟模式,可以强制增大堆大小。这将导致GC努力避免G2集合。监控RAM使用情况,并在消耗达到5GB时禁用低延迟模式

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

我不会这么做。您可以最大限度地获得2倍的吞吐量。你的CPU已经用完了,对吗?工作站GC不能扩展到多个核心,并且使CPU闲置

CLR的GC“适应”您的负载

它不知道你愿意容忍多少内存作为开销。在这里,您可能希望给应用程序提供5GB的堆,这样集合就少多了。GC没有内置的调优旋钮(主观上的注释:这是一个小问题)

通过在短时间内使用一种低延迟模式,可以强制增大堆大小。这将导致GC努力避免G2集合。监控RAM使用情况,并在消耗达到5GB时禁用低延迟模式

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


我不会这么做。您可以最大限度地获得2倍的吞吐量。你的CPU已经用完了,对吗?Workstation GC不能扩展到多个核心,并且使CPU闲置。

最好的办法是找出您正在分配的对象,并确保只分配您需要的对象,而不要在实例上保留超过需要的时间。Perfview是深入研究这一点的好工具。G2对象只是指具有长时间跨度的对象,因为它们是通过维护引用来持久化的,所以您是在需要完成时释放对象还是最终释放对象。GC确实会适应,事实上,它通常在内存压力下被调用,而不是在我们认为应该调用的时候,它是不确定的。请求一结束,对象就被释放,通常最多只活几秒钟——但在这几秒钟内,我们