-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
timeseries: fix memory leaks involving CardObserver and shareReplay #5254
Conversation
@@ -305,7 +306,7 @@ export class RunsTableContainer implements OnInit, OnDestroy { | |||
|
|||
const getFilteredItems$ = this.getFilteredItems$( | |||
this.allUnsortedRunTableItems$ | |||
).pipe(shareReplay(1)); | |||
).pipe(takeUntil(this.ngUnsubscribe), shareReplay(1)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind putting a comma after shareReplay(1) here so it formats on multiple lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tried, but unfortunately Prettier seems to undo the comma and remove the multiline, I think because this.getFilteredItems$(this.allUnsortedRunTableItems$)
did not fit onto one line.
Thanks for the review! |
…ensorflow#5254) This addresses 2 non-trivial sources of memory leaks observed when filtering tags in the Time Series dashboard. a) CardObserver used to track Elements that were destroyed via ngOnDestroy and stored them in a `Set<Element>`. Now with a WeakSet instead, we cover cases when the browser's IntersectionObserverEntry is not handled for some reason. b) The rxjs operator "shareReplay" has some known gotchas [1], [2]. When more observables subscribe to a source containing `shareReplay(1)` in its operator chain, the source remains subscribed even after the other observables unsubscribe. This change uses the `takeUntil(ngUnsubscribe$)` pattern to ensure any component using a `shareReplay` will not keep it subscribed after the component is gone. Alternatively we could use `refCount`, but this opts for the `takeUntil` pattern already used widely in the codebase. Manually checked that the dashboard still operates properly, and in Angular's dev mode, using a specific demo logdir, adding and clearing a "." tag filter has these characteristics: Before this change: 5.8 MB, 5.5K DOM nodes added each cycle After this change: 0.05 MB, <10 DOM nodes added each cycle Googlers, see b/196996936 [1] ReactiveX/rxjs#5034 [2] ReactiveX/rxjs#5931
…ensorflow#5254) This addresses 2 non-trivial sources of memory leaks observed when filtering tags in the Time Series dashboard. a) CardObserver used to track Elements that were destroyed via ngOnDestroy and stored them in a `Set<Element>`. Now with a WeakSet instead, we cover cases when the browser's IntersectionObserverEntry is not handled for some reason. b) The rxjs operator "shareReplay" has some known gotchas [1], [2]. When more observables subscribe to a source containing `shareReplay(1)` in its operator chain, the source remains subscribed even after the other observables unsubscribe. This change uses the `takeUntil(ngUnsubscribe$)` pattern to ensure any component using a `shareReplay` will not keep it subscribed after the component is gone. Alternatively we could use `refCount`, but this opts for the `takeUntil` pattern already used widely in the codebase. Manually checked that the dashboard still operates properly, and in Angular's dev mode, using a specific demo logdir, adding and clearing a "." tag filter has these characteristics: Before this change: 5.8 MB, 5.5K DOM nodes added each cycle After this change: 0.05 MB, <10 DOM nodes added each cycle Googlers, see b/196996936 [1] ReactiveX/rxjs#5034 [2] ReactiveX/rxjs#5931
This addresses 2 non-trivial sources of memory leaks observed when
filtering tags in the Time Series dashboard.
a) CardObserver used to track Elements that were destroyed via
ngOnDestroy and stored them in a
Set<Element>
. Now with a WeakSetinstead, we cover cases when the browser's IntersectionObserverEntry
is not handled for some reason.
b) The rxjs operator "shareReplay" has some known gotchas [1], [2].
When more observables subscribe to a source containing
shareReplay(1)
in its operator chain, the source remains subscribedeven after the other observables unsubscribe. This change uses the
takeUntil(ngUnsubscribe$)
pattern to ensure any component using ashareReplay
will not keep it subscribed after the component is gone.Alternatively we could use
refCount
, but this opts for thetakeUntil
pattern already used widely in the codebase.
Manually checked that the dashboard still operates properly, and in
Angular's dev mode, using a specific demo logdir, adding and clearing a
"." tag filter has these characteristics:
Before this change: 5.8 MB, 5.5K DOM nodes added each cycle
After this change: 0.05 MB, <10 DOM nodes added each cycle
Googlers, see b/196996936
[1] ReactiveX/rxjs#5034
[2] ReactiveX/rxjs#5931