Skip to content

Potentiel leak: NativeScript views not cleaned up on removal #1738

Closed
@m-abs

Description

@m-abs

Environment
Provide version numbers for the following components (information can be retrieved by running tns info in your project folder or by inspecting the package.json of the project):

  • CLI: 5.2.0
  • Cross-platform modules:
  • Android Runtime: 5.2.0
  • iOS Runtime:5.2.0
  • Plugin(s):
  • NativeScript-Angular: ~7.2.1
  • Angular: ~7.2.0

Describe the bug

While working on #1728 I think I’ve found a couple of memory leaks in nativescript-angular.

ListViewComponent/TemplatedItemsComponent items.
In onItemLoading(args) https://github.com/NativeScript/nativescript-angular/blob/master/nativescript-angular/directives/templated-items-comp.ts#L141-L181
The viewRef is bound to the args.view[NG_VIEW].
This is never cleared, so when the ListViewComponent is destroyed this reference still exists.
I suggest making this a WeakRef.

The factory functions in TemplatedItemsComponent._templateMap creates a circular reference and should be cleared in ngOnDestroy()

NativeScript views lives on after the angular app have been destroyed.
The native views are destroyed as expected but according to the Chrome debugger the NativeScript views lives on.
This is caused by the AppHostView not being cleared up on exit and the firstChild, lastChild and nextSibling references are not cleaned up.
The AppHostView is reused on next launch, so it shouldn’t itself be deleted but the children should.
Sidenote: AppHostView._ngAppRoot is a reference to the last Frame even after exit, this should be solved by deleting all its children on exit.

ViewUtils.removeChild(parent, child) doesn’t remove children recursively.
ViewUtils sets up the firstChild, lastChild and nextSibling references when a view is added, but doesn’t clear them up properly when a parent view is removes.

I suggest making removeFromQueue(parent, child) and removeFromVisualTree(parent, child) recursive to clear up the references.

PageRouterOutlet doesn’t clear up it’s children.
this.activated should be destroyed in ngOnDestroy()

NSLocationStrategy don’t have an ngOnDestroy()
This leaves correntOutlet with a reference to the destroyed PageRouterOutlet.

To Reproduce

  • Create a new nativescript angular app with: tns create --ng NAME
  • Launch the app on android in debug mode and start the Chrome debugger.
  • Close the app by tappen the back button, reopen and close the app a few times.
  • Go to the memory tab in the Chrome debugger and take a heap snapshot.
  • The snapshot will have N (= number of times the app has been opened) Frame'/ActionBar/Page/PageRouterOutlet, N*8 StackLayout` etc. The native views will have been destroyed.
    • If you inspect the Views a little closer you should see they hold references to each other via firstChild, lastChild and nextSibling

Note: It doesn't seem to matter how many times I call GC() or how long I wait.

Expected behavior

  • I expect the GC() to have collected the NativeScript Views.

Sample project

https://github.com/m-abs/tns-ng-app-lifecycle

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions