0

我有课

class A {
    IObservable<long> poll = new Observable.Interval(100 ms).Do((ms) => LoadData());

    void Subscribe() {
        poll.Subscribe();
    }
}

我有课

class B {
    IEnumerable<A> Items { get; }

    void Refresh() {
        Items = GetNewListWithNewJustCreatedInstances();
    }
}

用户多次订阅许多项目,然后他调用 Refresh() 从某个服务器重新加载项目(显然,他再次订阅了新项目)。所有旧订阅都会自动处理还是我应该实现这样的东西?

class A : IDisposable {
    void Dispose() {
        poll.Dispose();
    }
}

class B {
    void Refresh() {
        foreach (var item in Items) {
            item.Dispose();
        }
    }
}
4

1 回答 1

0

您的代码是多次内存泄漏的秘诀。见类似的问题

Rx 订阅永远保持活动状态,直到被释放、调用 OnComplete 或 OnError。垃圾收集不会清理它们。由于您没有处理并且Observable.Interval永远不会完成,因此每个订阅都会泄漏,直到您耗尽内存。A您的代码为每个 的实例以及显然多个A对象提供了多个订阅的可能性。

这是一些对 Linqpad 友好的代码来测试它:

void Main()
{
    var a0 = new A();
    a0.Subscribe();
    a0.Subscribe();
    a0.Subscribe();
    a0.Dispose();
    a0 = null;

    GC.Collect(); //Has no effect. Demonstrates Garbage collection doesn't help.
}

class A : IDisposable
{
    IObservable<long> poll = Observable.Interval(TimeSpan.FromMilliseconds(100)).Do(l => l.Dump());
    IDisposable disposable;
    public void Subscribe()
    {
        Dispose();
        //memory leak!!
        poll.Subscribe();

        //Use this instead
            //disposable = poll.Subscribe();
    }

    public void Dispose()
    {
        disposable?.Dispose();
    }
}

当内存泄漏行被取消注释并且安全的行被注释时,您会看到每个间隔弹出三个数字,每个订阅一个。当disposable-tracking 行未注释并且内存泄漏已注释掉时,您应该看不到任何输出。

于 2016-08-09T20:51:04.780 回答