EDIT
You could also check out RxJS: Why memory leaks occur when using a Subject.
I'd say that there will be no memory leaks.
This is based on my understanding as to why memory leaks actually occur.
Usually this sort of problems take place when the source is infinite(e.g will not complete/error, like a global service that is used by components).
For example, in Angular, a common pattern is to inject a app-scoped service into components and subscribe to one of the observable properties exposed by the service.
class Service {
private usersSrc = new Subject();
users$ = this.usersSrc.asObservable();
}
Then you'd do this in your component:
class FooComponent {
ngOnInit () {
this.subscription = this.service.users$.subscribe(() => {} /* callback */)
}
}
Note: this is just for demonstration purposes, as you'd want to use other approaches so that you won't have to manually subscribe, e.g async pipe
When users$
is subscribed, because users$
comes from usersSrc
, the newly created subscriber will be added to the Subject's list of subscribers. And that subscriber's next callback will be the () => {}
callback.
Now when the component is destroyed(e.g due to navigating to another route), if you don't do something like this.subscription.unsubscribe()
, that subscriber will still be part of that subscribers list. The unsubscribe
method would remove that subscriber from that list.
So, the next time the component is created and that ngOnInit
is created, a new subscriber will be added, but the old one would still be there if you didn't use this.subscription.unsubscribe()
.
I'd say that setting that source to null would be enough.
If the source happens to be a Subject
, you could also use Subject.unsubscribe
, although it may not make any difference.
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null!;
}
Here would be a simplified version. You could paste this in your console.
src = {
subscribers: [],
addSubscriber(cb) {
this.subscribers.push(cb);
return this.subscribers.length - 1
},
removeSubscriber(idx) {
this.subscribers.splice(idx, 1)
},
next (data) {
this.subscribers.forEach(cb => cb(data));
}
}
// the component
class Foo {
constructor () {
this.subIdx = src.addSubscriber(() => { console.log('foo') })
}
onDestroy () {
src.removeSubscriber(this.subIdx);
}
}
// usage
// creating a new component
foo = new Foo() // Foo?{subIdx: 0}
// sending data to subscribers
src.next('test')
// destroying the component - without calling `onDestroy`
foo = null
src.next('test') // the subscribers is still there
VM506:18 foo
foo = new Foo() // registering a new instance - Foo?{subIdx: 1}
src.next('test2')
foo
foo
foo.onDestroy()
src.next('test2')
foo