Skip to content

2.x: BoundedReplayBuffer temporarily leaks memory #6475

Closed
@nhaarman

Description

@nhaarman

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions