我有一个 Windows 控制台应用程序,它应该可以运行数天和数月而无需重新启动。该应用程序从 MSMQ 检索“工作”并对其进行处理。有 30 个线程同时处理一个工作块。
来自 MSMQ 的每个工作块大约为 200kb,其中大部分分配在单个 String 对象中。
我注意到在处理了大约 3-4 千个这样的工作块之后,应用程序的内存消耗非常高,消耗了 1 - 1.5 gb 的内存。
我通过分析器运行应用程序并注意到大部分内存(可能是 gig 左右)在大型对象堆中未使用,但结构是碎片化的。
我发现这些未使用的(垃圾收集的)字节中有 90% 是以前分配的字符串。那时我开始怀疑来自 MSMQ 的字符串被分配、使用然后解除分配,因此是碎片的原因。
我知道像 GC.Collect(2 or GC.Max...) 这样的东西不会有帮助,因为它们 gc 大对象堆但不压缩它(这是这里的问题)。所以我认为我需要缓存这些字符串并以某种方式重新使用它们,但由于字符串是不可变的,我将不得不使用 StringBuilders。
我的问题是:无论如何不改变底层结构(即使用MSMQ,因为这是我无法改变的)并且仍然避免每次都初始化一个新的字符串以避免分割LOH?
谢谢, 雅尼斯
更新:关于当前如何检索这些“工作”块
目前,这些在 MSMQ 中存储为 WorkChunk 对象。这些对象中的每一个都包含一个名为 Contents 的字符串和另一个名为 Headers 的字符串。这些是实际的文本数据。如果需要,我可以将存储结构更改为其他内容,如果需要,我可以将底层存储机制更改为 MSMQ 以外的其他内容。
目前我们在工作节点方面
WorkChunk 块 = _Queue.Receive();
所以在这个阶段我们可以缓存的东西很少。如果我们以某种方式改变结构,那么我想我们可以取得一些进展。无论如何,我们都必须解决这个问题,所以我们将尽一切可能避免浪费数月的工作。
更新:我继续尝试以下一些建议,并注意到无法在我的本地计算机上重现此问题(运行 Windows 7 x64 和 64 位应用程序)。这让事情变得更加困难 - 如果有人知道为什么,那么它真的会帮助在本地重新解决这个问题。