我有一个从大量 MSMQ 队列(目前大约 10000 个)读取的应用程序。我使用queue.BeginPeek
UInt32.MaxValue 超时从队列接收消息。当消息出现在队列中时,我对其进行处理并queue.BeginPeek
再次调用。所以我听所有的队列,但是消息处理是在线程池上完成的。
我注意到内存使用量缓慢增长(两周的工作导致从 200 MB 增长到 800 MB)。在调查了转储文件后,我看到了带有许多空闲对象的典型堆碎片图片(其中一些有大约几兆字节的大小)。并且孔之间有固定的物体。
在处理创建固定对象的非托管代码调用时,这似乎很常见。但是我在互联网上没有找到任何解决方案。
.NET 中的内存管理是否如此纯粹,以至于它甚至不允许完成如此简单的场景,或者我错过了什么?
编辑:我对示例应用程序进行了一些调查。在为新对象分配内存时,固定对象之间的空洞(空闲内存区域,所谓的空闲对象)被 GC 重用。但是在我的生产应用程序中,固定对象是长期存在的,它们最终出现在第二代,它们之间有孔(因为 GC 只是移动了分隔代的边界)。由于我几乎没有正常的长寿命对象,因此我在转储文件的第二代中看到了这个漏洞。
所以我的应用程序的内存消耗可以增长到 10000*(孔的平均大小)。(10000 是将来还可以增加的队列数)。我目前不知道如何解决这个问题。唯一的方法是不时重新启动应用程序。
再一次我只能问,为什么 .NET 没有用于固定对象的单独堆?(也许这是新手问题)。目前我看到调用使用非托管代码的异步操作可能会导致内存问题。