使用MSMQ异步IO时的.NET堆碎片

str*_*nov 5 .net msmq memory-fragmentation

我有一个从大量MSMQ队列中读取的应用程序(目前约为10000).我使用queue.BeginPeekUInt32.MaxValue超时来从队列接收消息.当消息出现在队列中时,我处理它并queue.BeginPeek再次调用.所以我监听所有队列,但是消息处理是在线程池上完成的.

我注意到内存使用量缓慢增长(两周的工作量从200 MB增长到800 MB).在调查转储文件后,我看到了典型的堆碎片图片,其中包含许多自由对象(其中一些大小约为几兆字节).并且在孔之间存在固定物体.

在处理对非托管代码的调用时,这似乎是常见的情况,这些代码创建了固定对象.但我没有在互联网上找到任何解决方案.

那么.NET中的内存管理是如此纯粹,它甚至不允许完成这样简单的场景,或者我想念一些东西?

编辑:我在示例应用程序中进行了一些调查.在为新对象分配内存时,GC会重用固定对象之间的孔(可用内存区,即所谓的自由对象).但是在我的生产应用程序中,固定物体是长寿命的,它们最终出现在第二代,它们之间有孔(因为GC只是移动了分隔世代的边界).因为我的普通长寿对象很少,所以我在转储文件中看到了第二代的漏洞.

因此,我的应用程序的内存消耗可以增长到10000*(平均大小的孔).(10000是将来也可以增加的队列数).我现在不知道如何解决这个问题.唯一的方法是不时重新启动应用程序.

我再一次只能问,为什么.NET没有针对固定对象的单独堆?(也许这是新手问题).目前,我发现调用与非托管代码一起使用的异步操作可能会导致内存问题.

Mar*_*age 4

查看 MSMQ 托管包装器的源代码后,您似乎在使用 API 时偶然发现了一个真正的问题。调用BeginPeek将创建一组属性,然后在传递给非托管 API 之前固定这些属性。仅当收到消息时,这些属性才会取消固定,但要继续接收消息,您必须BeginPeek在此时调用,从而随着时间的推移导致内存碎片。

如果这种碎片确实是一个问题,我能想到的唯一办法是每隔一个小时左右,您应该取消对 的所有调用BeginPeek,强制进行垃圾收集,然后恢复正常的侦听操作。这应该允许垃圾收集器处理碎片。