Skip to content

2.x: BoundedReplayBuffer temporarily leaks memory #6475

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions