我有class
class A {
IObservable<long> poll = new Observable.Interval(100 ms).Do((ms) => LoadData());
void Subscribe() {
poll.Subscribe();
}
}
我有class
class B {
IEnumerable<A> Items { get; }
void Refresh() {
Items = GetNewListWithNewJustCreatedInstances();
}
}
User多次订阅多个项目,然后调用Refresh()从某个服务器重新加载项目(显然,他再次订阅新项目)。所有旧的订阅会自动处理吗?还是我应该实现类似这样的东西?
class A : IDisposable {
void Dispose() {
poll.Dispose();
}
}
class B {
void Refresh() {
foreach (var item in Items) {
item.Dispose();
}
}
}
你的代码是一个多重内存泄漏的配方。见类似问题。
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();
}
}
当没有注释内存泄漏行,而注释了安全行时,您将看到每个间隔弹出三个数字,一个数字代表一个订阅。当一次性跟踪行未被注释,并且内存泄漏被注释掉时,您应该看不到任何输出。