.NET Garbagecollector麻烦。 阻挡15-40分钟

一些事实:我们开发了wcf服务,充当客户端和数据库之间的层。 它是自主设备并作为Windows服务运行。

该服务保留了几个缓存,其中最大的内存大约为1-2gb。 总内存使用量通常约为5-8gb。 连接是双工的,使用tcp协议,序列化使用protobuf-net。 我们的连接客户端数量通常在1000-1500之间。 该服务器是一个8核xeon的新型号,内存为64GB,并且只运行该服务。

问题:经过一段时间后,从一天到一周,服务变得非常缓慢。 需要0.5秒的请求可能需要一分钟。 此行为持续15-40分钟或直到服务重新启动。

我们做了什么:我们检查了服务器的网络和网络连接,没有问题。 从f.eks开始,这段时间CPU利用率有所上升。 平均30%至40-50%。 我们已经进行了内存转储,代码中没有阻止用户的逻辑锁,也没有多少活动。 我们最新的领导是垃圾收集器。 在perfmon中,我们可以看到“gc中的%time”不断超过90%,(90-97%)并且收集计数增加。 GC0和GC1都有。 我们怀疑还有阻止GC2运行,但我们不得不重新启动服务,因为它正在生产中,因此在我们运行perfmon的5分钟窗口期间它没有计数。 内存使用量为7,6 Gb。 注意:呼叫突然上升,因此呼叫到达那里,但服务不处理它们。

我的问题是,垃圾收集器能否处于运行状态并持续阻塞超过15分钟? 或者问题可能与其他问题有关?

我们的服务在工作站模式和延迟模式下运行GC:交互式我们现在已将其更改为Server和SustainedLowLatency,并希望这会有所帮助。 如果它是垃圾收集器,还有什么我们可以做的吗?

编辑:大容量内存使用是设计的,缓存中的数据很大,并且有更多的可用内存。

过多的垃圾收集通常是由代码问题引起的。 您要么在短时间内创建太多对象,要么继续分配内存而不释放它。

MSDN上实际上有一个广泛的清单可以帮助您诊断问题。

一个非常大的GC2意味着那里的对象幸存了多个垃圾收集,这意味着它们在内存中保存了更长的时间。 这可能是您问题的根本原因。 也许有一种缓存机制可以使用一些调优/保留策略(删除长时间未使用的数据)。

我有类似的情况。 使用带有WCF的protobuf进行客户端通信的服务中的大型数据库数据缓存。 缓存不仅仅适用于客户端,业务层使用缓存来执行操作。 服务的内存占用量可以介于2到10 GB之间。 我在8小时不活动后释放一段缓存。 该机器有8个虚拟内核和32 GB内存。 我正在使用.Net 4.5.1。

一旦从数据库加载缓存,GC就会消耗98%的CPU一小时。 在我们的两个案例中,有趣的一点是没有记忆压力。

我认为GC是执行的,因为在GC尝试为所有线程保留可用内存的地方发生了一些变化。 由于一个线程在加载缓存时分配了大量内存,因此GC启动了。我必须做几件事来解决它。

1)从缓存中删除了元组。 我使用它们作为字典键,它们对StructuralEquality的实现非常糟糕。 它将所有属性作为对象进行比较,因此对于属性值进行大量装箱,这些属性必须在某些时候进行垃圾回收。

2)当替换用作键的元组时,我不能简单地用结构替换它们而不实现Equals,因为值比较使用reflection并且它太昂贵所以我最终创建了一个通用对结构。 我决定使用结构来删除数组中的对象数量。

3)要删除元组,我必须创建自己的Pair结构,使用默认等于属性类型的属性进行比较。 与PowerCollections创建的function完全相同。