Может Observable.Timer() привести к утечкам памяти?
Недавно я заметил небольшую ошибку в моем коде, которая использует Reactive Extensions. Я подписывался на Таймер, но никогда не выбрасывал свою подписку. Это привело к утечке памяти.
Я создал фрагмент, который подчеркивает эту опасность:
while (true)
{
Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)).Subscribe(Console.WriteLine);
}
Это нормальное поведение?
Разве планировщик не должен содержать слабую ссылку на таймер для сбора мусора, когда подписчики теряют связь с остальной частью приложения?
3 ответа
Это нормально, и это особенность.
Семантика для Subscribe() - это прослушивание навсегда, или пока Disposed() или OnCompleted(), или OnError(), который когда-либо будет первым.
Вы можете сохранить ссылку на подписку и даже объединить их с CompositeDisposable
, но обычный метод управления IObservable
время жизни в противном случае бесконечного оператора (как Timer
) с помощью оператора, который применяет правила завершения к другому, например, Take
(принять значения х), TakeWhile
(принять значения в то время как f(x)
возвращает true) или TakeUntil
(принимать значения до тех пор, пока другая последовательность, y, не выдаст значение или не завершится).
Работающие Rx операторы не будут автоматически GC'd, если они не завершили. Timer
/ Interval
Например, оба рекурсивно планируют свое следующее значение, используя IScheduler
и экземпляры по умолчанию различных планировщиков все доступны через статические свойства Scheduler
, Это делает работающий оператор всегда укоренившимся и, следовательно, недоступным для GC.
Я не согласен с ответом. То, что вы по существу делаете, является избыточным, поскольку вы используете бесконечный цикл для создания последовательных наблюдаемых, отсюда и утечка памяти. Удалите цикл while и просто используйте один Observable.Timer или, что еще лучше, используйте Observable.Interval. Просто один случай, когда вам это больше не нужно, позвоните на него.