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