TPL Dataflow资源未被释放

4

我有一个如下设置的流程:

_publisherQueue = CreateBuffer();
var batchingBlock = CreateBatchBlock(options.BatchSize);
var debounceBlock = CreateDebounceBlock(options.DebounceInterval, batchingBlock.TriggerBatch);
var publishBlock = CreatePublishBlock();
var groupByTopicBlock = CreateGroupByTopicBlock(publishBlock);

_publisherQueue.LinkTo(debounceBlock, new DataflowLinkOptions { PropagateCompletion = true});
debounceBlock.LinkTo(batchingBlock, new DataflowLinkOptions { PropagateCompletion = true });
batchingBlock.LinkTo(groupByTopicBlock, new DataflowLinkOptions { PropagateCompletion = true });

其中:

  • CreateDebounceBlock 返回一个转换块(带有计时器来触发batchblock
  • CreateGroupByTopicBlock 返回一个ActionBlock,其Action触发由CreatePublishBlock返回的Action block

我不能处理这些链接,因为该流应在程序的整个生命周期内存在(在此示例中为Windows服务)。

我注意到每次调用_publisherQueue(它是一个BufferBlock)都会使用一些内存,这是正常的。但是,在进程完成后,分配的内存没有被释放。

这令人担忧,因为这是一个长时间运行的过程,将在随机时间间隔接受输入。

这是我第一次尝试使用TPL,所以很可能我没有正确处理。但是,我不确定需要处置什么,因为我需要这些结构在整个程序的生命周期内保持活动状态。


“进程已完成”是什么意思,你是如何测量内存是否仍在分配的? - Peter Ritchie
@PeterRitchie 使用VS中的诊断工具。“进程已完成”意味着我向缓冲区添加了一些内容,它通过了整个流程并得到了发布。此时,我期望为执行该流程分配的内存被释放。 - Jonny
为什么?如果您不告诉流程已经完成并使用 Complete(),那么就没有释放任何东西的理由。您可以在下一纳秒内发布另一条消息。流程应该处理大量的消息,特别是在服务中使用时。 - Panagiotis Kanavos
3
在“诊断工具”窗口中看到的内存很可能可以被垃圾回收。除非垃圾回收运行(用橙色标记显示),否则它不会被回收。或者你可能有一个内存泄漏。在内存选项卡中拍摄两个快照,以查看哪些新对象存活下来以及它们被分配到了哪里。 - Panagiotis Kanavos
@PanagiotisKanavos 感谢您的评论。实际上,Complete 方法是我最感兴趣的。我不确定何时调用 Complete。我同意我可能会在下一纳秒发布另一条消息,因此如果我正确理解 Complete 方法的作用,我只能在程序关闭时调用 Complete 方法。 - Jonny
@jonny 这就是数据流的挑战:创建一个协议,使得“完成”是明确且可检测的。 - Peter Ritchie
1个回答

2
我对这部分内容有所担忧:

CreateGroupByTopicBlock 返回一个 ActionBlock,其 Action 触发由 CreatePublishBlock 返回的 Action 块。

看起来像是一个闭包,在编译成内部类时可能会导致内存泄漏,因为它会将所有引用存储在字段中。您应该使用一些内存分析器(如内置的 VS 分析器或一些外部工具,如 dotTrace)来调查您的应用程序,并查看是否有任何对象被该闭包引用,如果有,则可以重写您的逻辑以避免在代码中使用不必要的闭包。

1
闭包很容易导致内存泄漏。刚刚解决了一个与TPL相关的巨大问题。 - Jeremy Morren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接