Description
When using Observable.replay(N)
, the BoundedReplayBuffer
keeps up to N+1
items in its buffer. When using replay(1)
for example, it keeps a reference to the most recent item, but also the previous, stale item.
Take for example this trivial snippet of code that provides an available Android View
as a stream:
val eventsSubject = BehaviorSubject.create<Event<View>>()
val view: Observable<Option<View>> = eventsSubject
.map { event ->
when(event) {
is Attached<View> -> Option.just(event.view)
is Detached -> Option.empty()
}
}
.replay(1).refCount()
The replay(1)
call suggests a single value is cached, but the implementation keeps a strong reference to the previous item as well.
Since this happens as a hidden side effect and rather counter intuitively, it is easy to accidentally leak memory -- even when the client code seems to be careful about it. Especially with Android Views referencing Activity contexts this is problematic.
#5282 proposed a fix for this at the cost of an extra Node
allocation, which turned out to be unwanted.
The proposed alternative there refers to RxJava2Extensions#cacheLast, but this only emits the very last item, not intermediates.