我在我的 rebus 处理程序中看到了一个非常奇怪的行为,它自托管在 exe 中。在使用 bus.send 方法发送响应后,它会立即添加一些进程消耗的内存。我尝试使用内存配置文件查找对象图,发现 rebus 在某处以序列化格式保存响应消息。对象图显示在根的层次结构之下。
System.Message --> CachedBodyMessage --> 流
如果有人知道这件事,请给我一些指示。
我在我的 rebus 处理程序中看到了一个非常奇怪的行为,它自托管在 exe 中。在使用 bus.send 方法发送响应后,它会立即添加一些进程消耗的内存。我尝试使用内存配置文件查找对象图,发现 rebus 在某处以序列化格式保存响应消息。对象图显示在根的层次结构之下。
System.Message --> CachedBodyMessage --> 流
如果有人知道这件事,请给我一些指示。
我知道内存泄漏是一个严重的问题,但我认为 Rebus 不太可能包含内存泄漏。
这种信念源于这样一个事实,即我已经在生产环境中运行 Windows 服务托管的 Rebus 端点已有 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 msg/s 并在每条消息中包含一个 64 KB 的随机字符串有效负载,并且我已经跟踪了近四个小时的内存使用情况。如您所见,它看起来不像内存泄漏。
为了确定,我会让它在一天的剩余时间里运行。
也许你可以告诉我更多关于你为什么怀疑首先存在内存泄漏的信息?
更新:
从跟踪中可以看出,它现在已经运行了 7 个小时,因此同一进程已发送和使用了超过 1,200,000 条包含超过 70 GB 数据的消息。如果缓存的消息体泄漏,我很确定我们能够看到图表上出现了一些上升。