core
core copied to clipboard
Unsubscribe from "stream" does not clean up internal subscriptions
I'm submitting a ... (check one with "x")
[x] bug report => check the FAQ and search github for a similar issue or PR before submitting
[ ] support request => check the FAQ and search github for a similar issue before submitting
[ ] feature request
Current behavior When I unsubscribe from the Observable returned by a "stream" method call, an internal subscription stays in memory.
Expected/desired behavior When I unsubscribe from a stream also the internal stuff is unsubscribed.
Reproduction of the problem http://plnkr.co/edit/fIi2Xl0XVpl5eXQYT7GP?p=preview
I tried to make a plnkr that actually did what I wanted to show but it was not very easy. This plnkr subscribes to a single string each 3 seconds and unsubscribes a second later. To then see the memory leak, I made heap snapshots (after running gc of course) in Chrome. The number of "Subscriber" objects keeps increasing. The gc root path of all the objects that remain in memory look like:
destination in MergeMapSubscriber @1247973
parent in InnerSubscriber @1247983
destination in SwitchMapSubscriber @1247989
generatorOrNext in system / Context @1247995
context in () @1248001
_complete in SafeSubscriber @1248005
destination in Subscriber @1247827
[18] in Array @943305
observers in EventEmitter @943251
onLangChange in TranslateStore @939611
store in TranslateService @939609
translate in AppComponent @941593
So it seems like the stream method does not clean up the subscription to onLangChange. I'm not sure whether this is a shortcoming of ngx translate or the rxjs switchMap/concat implementation by the way!
What is the expected behavior? No memory leak!
-
ngx-translate version: 8.0.0
-
Angular version: 5.0.2
-
Browser: [all? | Chrome]
Did you try to complete it instead of just unsubscribing ? I know that it's not a fix, but it could be a workaround for now
Tried it in the plnkr now. Unfortunately I have the same results ... The workaround for now is to do a get and manually subscribe/unsubscribe to the onLangChange.
Thanks for the report as I was struggling with large memory leak issues in a medium-size app for some days now.
In fact, because of this memory leak you reported, the component (and ALL its children) subscribing (through async pipe in my case) to the observable from the .stream()
call wasn't properly removed from memory (even after a garbage collector).
It can cause very large memory leak when you have some big nested components.
By the way thanks for the workaround, I have written a simple helper function which I use everywhere I was using .stream()
previously :
export function streamTranslate(translateService: TranslateService, keys: string | Array<string>, params?: any): Observable<any> { return translateService.onLangChange.pipe( startWith({}), switchMap(() => params ? translateService.get(keys, params) : translateService.get(keys)) ); }
Hi, Is this issue still valid? It's better use the workaround or this bug was fixed?
Hi guys, i have the same problem right now with ngx-translate v13. For real i'll must unsubscribe manually stream ? because the get method not change when onLangChange emit the new value and we must use the stream method. For now i use the tzoratto fix and manually unsubscribe observale in ondestroy event. Any updates?
Thanks for the report as I was struggling with large memory leak issues in a medium-size app for some days now.
In fact, because of this memory leak you reported, the component (and ALL its children) subscribing (through async pipe in my case) to the observable from the
.stream()
call wasn't properly removed from memory (even after a garbage collector).It can cause very large memory leak when you have some big nested components.
By the way thanks for the workaround, I have written a simple helper function which I use everywhere I was using
.stream()
previously :
export function streamTranslate(translateService: TranslateService, keys: string | Array<string>, params?: any): Observable<any> { return translateService.onLangChange.pipe( startWith({}), switchMap(() => params ? translateService.get(keys, params) : translateService.get(keys)) ); }
Hi,
The problem is still present (2022)?
same problem, any update (2023)?