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();
    }
}

メモリ リークが発生している行のコメントを解除し、安全な行のコメントを解除すると、サブスクリプションごとに 1 つずつ、間隔ごとに 3 つの数値が表示されます。Disposable-tracking 行のコメントが外され、メモリ リークがコメント アウトされている場合、出力は表示されません。

于 2016-08-09T20:51:04.780 に答える