RxJS Observable subscription, why if we do not unsubscribe it causes memory leak?

Viewed 256

There is a lot about this subject already, I went through a lot of stack but could not find a clear answer.

I am wondering why a Subscription is still active when it does not exist anymore in the scope, to illustrate :

Observable myData$ = Observable<Data>; // being set above

someFn(): void => {
  let subscription = myData$.subscribe(data => console.log(data));
}

someFn();

//code continue

I am already aware that it causes memory leak etc. What I want to understand is how does it happen ?

From the official documentation :

With observable.subscribe, the given Observer is not registered as a listener in the Observable. The Observable does not even maintain a list of attached Observers.

In my understanding the Subscription above should be garbage collected and so not active anymore ? How does the memory leak occurs ?

1 Answers

I'd say it depends on myData$ observable.

If it automatically completes, then you should not worry about unsubscribing from it.

But if it doesn't, then here is why I think you should manually unsubscribe.

Suppose you have a shared service, SharedService, which has a private BehaviorSubject and exposes it with the asObservable() method.

class SharedService {
  private userSbj = new BehaviorSubject({});

  user$ = this.userSbj.asObservable();
}

Let's see what happens when ComponentA subscribes to user$ and consumes it:

class ComponentA {
  constructor (private sharedService: SharedService) { }

  ngOnInit () {
    this.userAge$ = this.sharedService.user$.pipe(pluck('

    this.subscription = this.userAge$.subscribe(data => console.log(data));
  }
}

userAge$ comes from user$. But remember that user$ is just BehaviorSubject.asObservable(). What this means is that when a new subscriber is registered, it will be added to the subscribers list maintained by the BehaviorSubject.

If you are not manually unsubscribing, then that subscriber will still be part of that , even though the component might be destroyed. That subscribers list still keeps a reference to that subscriber. But, if you do unsubscribe, say in ngOnDestroy:

this.subscription.unsubscribe();

Then, that subscriber will be removed from that subscribers list, so, since the subscriber is no longer referenced from any other place, you will not have any memory leaks.


This is what happens when a BehaviorSubject is being subscribed to:

_subscribe(subscriber: Subscriber<T>): Subscription {
  const subscription = super._subscribe(subscriber);
  if (subscription && !(<SubscriptionLike>subscription).closed) {
    subscriber.next(this._value);
  }
  return subscription;
}

In super._subscribe(subscriber), super refers to Subject, because BehaviorSubject extends Subject:

Subject._subscribe:

// adding to the subscribers(observers) list
this.observers.push(subscriber);
return new SubjectSubscription(this, subscriber);

SubjectSubscription plays an important role here, since it's responsible for removing the subscriber from the subscribers list.

Related