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

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

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

1 ответ

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

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

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

Вы упоминаете "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 200000 сообщений, содержащих более 70 ГБ данных. Если бы кешированные тела сообщений протекали, я вполне уверен, что мы могли бы увидеть что-то на графике.

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

Другие вопросы по тегам