Фрагментация кучи .NET при использовании асинхронного ввода-вывода MSMQ

StackOverflow https://stackoverflow.com//questions/12674074

  •  12-12-2019
  •  | 
  •  

Вопрос

У меня есть приложение, которое считывает большое количество очередей MSMQ (на данный момент около 10 000).я использую queue.BeginPeek с тайм-аутом UInt32.MaxValue для получения сообщения из очереди.Когда сообщение появляется в очереди, я обрабатываю его и вызываю queue.BeginPeek снова.Поэтому я слушаю все очереди, но обработка сообщений выполняется в пуле потоков.

Заметил, что использование памяти медленно растёт (за две недели работы рост с 200 Мб до 800 Мб).Изучив файл дампа, я вижу типичную картину фрагментации кучи со множеством свободных объектов (некоторые из них имеют размер около нескольких мегабайт).А между отверстиями есть приколотые предметы.

Кажется, это обычная ситуация при работе с вызовами неуправляемого кода, создающего закрепленные объекты.Но в инете решения не нашел.

Так управление памятью в .NET настолько чистое, что не позволяет выполнять даже такие простые сценарии, или я что-то упускаю?

Редактировать : Я провел некоторые исследования в примерах приложений.Дыры (зоны свободной памяти, так называемые свободные объекты) между закрепленными объектами повторно используются сборщиком мусора при выделении памяти для новых объектов.Но в моем производственном приложении закрепленные объекты живут долго, и, наконец, во втором поколении они появляются с дырами между ними (потому что GC просто сдвигает границу, разделяющую поколения).Поскольку у меня действительно мало нормальных долгоживущих объектов, я вижу эти дыры во 2-м поколении в файле дампа.

Таким образом, потребление памяти моим приложением может вырасти до 10000*(средний размер дыры).(10000 — количество очередей, которое в будущем также может увеличиться).На данный момент у меня нет идей, как это исправить.Единственный способ — время от времени перезапускать приложение.

Еще раз могу только спросить, почему в .NET нет отдельной кучи для закрепленных объектов?(возможно, это вопрос новичка).На данный момент я вижу, что вызов асинхронных операций, работающих с неуправляемым кодом, может вызвать проблемы с памятью.

Это было полезно?

Решение

После взгляда на исходный код для управляемой обертки для MSMQ кажется, что вы наткнулись на подлинную проблему, используя API.Вызов BeginPeek создаст сборник свойств, которые затем загружен до передачи в неуправляемую API.Только когда получено сообщение, являются ли эти свойства unpinked, но для продолжения получения сообщений вы должны позвонить в BeginPeek в этот момент, ведущий к фрагментации памяти со временем.

Если эта фрагментация является реальной проблемой, единственным взлом, с которым я могу придумать, является каждый час или около того, вы должны отменить все вызовы на BeginPeek, заставляйте сборку мусора, а затем возобновить обычные операции прослушивания.Это должно позволить сборщику мусора обрабатывать фрагментацию.

Другие советы

Что ж, если проблема связана с долговечностью закрепленных объектов, то простым решением будет использование тайм-аута для BeginPeek с более короткой продолжительностью, чтобы не дать им перейти в следующее поколение.После каждого тайм-аута и EndPeek вы можете переиздать BeginPeek.В зависимости от того, когда свойства, на которые ссылался Мартин, созданы и удалены, вам, возможно, придется воссоздать объект очереди (очевидно, не саму очередь, а только измененную оболочку).Хотя, если повезет, вам не придется заходить так далеко.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top