此Reactive Extensions代码会泄漏内存吗?

时间:2013-08-03 02:43:03

标签: c# system.reactive

我编写了一些代码,将FileSystemWatcher的{​​{1}}事件转换为可观察的序列。

我的目标是将所有文件系统的两个分区更改为单独的流并限制它们。

例如,如果我有10个不同的文件在半秒内改变3次,我只会为每个文件获得一次通知。

我担心的是Changed运算符。为了实现这一目标,(我假设)它需要随着时间的推移不断建立群体并消耗少量内存。

这会导致“泄漏”,如果是,我该如何预防呢?

GroupBy()

2 个答案:

答案 0 :(得分:4)

是的,对于每个新密钥,GroupBy创建一个Subject,并维护这些主题的字典。而且你订阅了这些。所以这是一小部分内存,随着时间的推移会增长而无需释放旧条目。您真正需要的是在节流计时器到期时移除密钥。我想不出用内置运算符做这个的方法。所以你需要一个自定义操作员。这是一个刺。

public IObservable<T> ThrottleDistinct<T>(this IObservable<T> source, TimeSpan delay)
{
    return Observable.Create(observer =>
    {
        var notifications = new Subject<IObservable<T>>();
        var subscription = notifications.Merge().Subscribe(observer);
        var d = new Dictionary<T, IObserver<T>>();
        var gate = new object();
        var sourceSubscription = new SingleAssignmentDisposable();
        var subscriptions = new CompositeDisposable(subscription, sourceSubscription);
        sourceSubscription.Disposable = source.Subscribe(value =>
        {
           IObserver<T> entry;
           lock(gate)
           {
             if (d.TryGetValue(value, out entry))
             {
               entry.OnNext(value);
             }
             else
             {
               var s = new Subject<T>();
               var o = s.Throttle(delay).FirstAsync().Do(() =>
               {
                 lock(gate)
                 {
                   d.Remove(value);
                 }
               });
               notifications.OnNext(o);
               d.Add(value, s);
               s.OnNext(value);
             }
          }
        }, observer.OnError, notifications.OnCompleted);

        return subscriptions;
    });
}

...
Observable.FromEventPattern(...)
    .Select(e => e.EventArgs.FullPath)
    .ThrottleDistinct(TimeSpan.FromSeconds(1))
    .Subscribe(...);

答案 1 :(得分:1)

根据布兰登的回答,受试者将会成长,无法被收回*。我在这里泄漏内存的主要担心是你没有捕获订阅!即

res.Subscribe(...

必须替换为

subscription = res.Subscribe(...

如果您没有捕获订阅,则永远不会丢弃订阅,因此您永远不会释放事件处理程序,因此您有“泄漏内存”。显然,如果你不在某处实际处理订阅,这是没用的。

*好吧,如果他们完成了那么他们将被自动处理,这样就行了。当FileDeleted事件发生时,您可以查看完成序列吗?