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