Следует ли утилизировать одноразовые предметы в коллекции до возобновления сбора?
У меня урок
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();
}
}
}
1 ответ
Ваш код является рецептом для нескольких утечек памяти. Смотрите аналогичный вопрос.
Подписки 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();
}
}
Когда строка утечки памяти не закомментирована, а безопасная закомментирована, вы увидите три числа, всплывающих за интервал, по одному для каждой подписки. Если строка одноразового отслеживания не закомментирована, а утечка памяти закомментирована, вы не увидите выходных данных.