Утечка памяти при отправке ответа от обработчика ребуса

Я заметил очень странное поведение в своем обработчике ребуса, который размещен в exe. Сразу после отправки ответа с помощью метода bus.send добавляется память, потребляемая процессом. Я попытался найти граф объектов, используя профиль памяти, и обнаружил, что ребус где-то хранит ответное сообщение в сериализованном формате. Граф объектов отображался ниже иерархии до корня.
System.Message --> CachedBodyMessage --> поток

Дайте мне несколько указателей, если кто-нибудь знает об этой вещи.


person priyank brahmbhatt    schedule 15.10.2013    source источник


Ответы (1)


Я понимаю, что утечка памяти вызывает серьезную озабоченность, но я считаю, что маловероятно, что Rebus должен содержать утечку памяти.

Это убеждение основано на том факте, что я использую конечные точки Rebus, размещенные в службе Windows, в производственной среде уже 1,5 года, и некоторые из них (например, менеджеры времени ожидания) иногда работают в течение нескольких месяцев без перезапуска.

Однако я хотел бы быть абсолютно пуленепробиваемым, поэтому я готов исследовать проблему, о которой вы сообщаете.

Вы упоминаете «CachedBodyMessage» — судя по названиям полей внутри System.Messaging.Message, похоже, что это что-то внутри MSMQ. Чтобы попытаться воспроизвести вашу проблему, я написал следующий тест:

[Test, Ignore("Only works in RELEASE mode because otherwise object references are held on to for the duration of the method")]
public void DoesNotLeakMessages()
{
    // arrange
    const string inputQueueName = "test.leak.input";
    var queue = new MsmqMessageQueue(inputQueueName);
    disposables.Add(queue);

    var body = Encoding.UTF8.GetBytes(new string('*', 32768));
    var message = new TransportMessageToSend
                    {
                        Headers = new Dictionary<string, object> { { Headers.MessageId, "msg-1" } },
                        Body = body
                    };

    var weakMessageRef = new WeakReference(message);
    var weakBodyRef = new WeakReference(body);


    // act
    queue.Send(inputQueueName, message, new NoTransaction());
    message = null;
    body = null;

    GC.Collect();
    GC.WaitForPendingFinalizers();

    // assert
    Assert.That(weakMessageRef.IsAlive, Is.False, "Expected the message to have been collected");
    Assert.That(weakBodyRef.IsAlive, Is.False, "Expected the body bytes to have been collected");
}

который проверяет, что отправленное транспортное сообщение собрано должным образом (хотя будет делать это только в режиме RELEASE из-за того, как режим DEBUG удерживает ссылки на объекты в пределах области действия)

Сейчас я попробую запустить пример TimePrinter и оставлю его включенным на некоторое время, чтобы посмотреть, смогу ли я воспроизвести проблему. Если вы наткнетесь на дополнительную информацию, например, о. какие именно объекты протекают, это было бы очень полезно.

Еще раз спасибо, что нашли время сообщить мне о своих опасениях :)

Последующие действия:

Я модифицировал образец TimePrinter, чтобы он отправлял 50 сообщений в секунду и включал в каждое сообщение полезную нагрузку случайной строки размером 64 КБ, и я отслеживал использование памяти в течение почти четырех часов. Как видите, это не похоже на утечку памяти.

Трассировка памяти Perfmon

Я оставлю его включенным до конца дня, просто чтобы быть уверенным.

Может быть, вы можете рассказать мне больше о том, почему вы подозреваете, что произошла утечка памяти?

Обновление:

Как видно из трассировки, он работает уже 7 часов, и, таким образом, одним и тем же процессом было отправлено и использовано более 1 200 000 сообщений, содержащих более 70 ГБ данных. Если бы кешированные тела сообщений просачивались, я почти уверен, что мы смогли бы увидеть рост на графике.

Трассировка памяти Perfmon 2

person mookid8000    schedule 17.10.2013