Ngx-datatable: Memory leak issue (seems to be related to ResizeableDirective and Renderer2.createElement)

Created on 12 Sep 2018  路  4Comments  路  Source: swimlane/ngx-datatable

I'm submitting a ... (check one with "x")

[ x ] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior
There appears to be a permanent memory leak after 11.1.6 version. It can be reproduced in Angular 5 application, when datatable component is used inside views for different routes. Switching between routes back and forth makes overall number of DOM nodes to grow in Chrome browser. There is no memory leak issue with 11.1.5 version. In addition, there are lot of DataTableComponent instances and its children if take a memory snapshot.

Expected behavior
There should be no memory leak.

Reproduction of the problem

  1. Install 11.1.5 version of library and switch between routes with datatable component for route views back and forth - no memory leak.
  1. Do the same but with 11.1.6 - there is a memory leak - DOM nodes grow and consumed memory as well. Memory snapshot outputs equal number of datatable instances to navigation between routes.

After more detailed investigation, I found out that memory leak disappears for 11.1.6 version in case if disable resizing for column:

<ngx-datatable-column [resizeable]="false">

After looking into source code of ResizeableDirective I can see that Renderer2 was used:

ngAfterViewInit(): void {
    const renderer2 = this.renderer;
    if (this.resizeEnabled) {
      const node = renderer2.createElement('span');
      renderer2.addClass(node, 'resize-handle');
      renderer2.appendChild(this.element, node);
    }
  }

New element is created, but it's not removed from renderer on component destroy - please see https://stackoverflow.com/questions/44465653/what-is-the-correct-way-to-destroy-an-element-created-with-renderer2

Finally, I tried other version of library and found out that fix with disabling column resize doesn't work starting from 11.2.0 version and memory leak is present again. Looking into source code of ResizeableDirective I see next:

ngAfterViewInit(): void {
  const renderer2 = this.renderer;
  const node = renderer2.createElement('span');
  if (this.resizeEnabled) {
    renderer2.addClass(node, 'resize-handle');
  } else {
    renderer2.addClass(node, 'resize-handle--not-resizable');
  }
  renderer2.appendChild(this.element, node);
}

Element is created with Renderer2 doesn't matter on condition and that's why workaround doesn't help.

I recommend to keep reference on "node" and remove it inside "ngOnDestroy". Also inspect code for same case with Renderer2 usage and apply same changes there as well.

What is the motivation / use case for changing the behavior?
Continue using library and have no memory leaks.

Please tell us about your environment:
MacOS, WebStroms, ng

  • Table version:
    11.1.6 and 11.2.0. I was trying with 13.1.0 and had same memory leak.

  • Angular version:
    5.2.11

  • Browser: Chrome 68.0.3440.106

  • Language: "typescript": "2.4.2"

Most helpful comment

Any updates on this ticket? It appears to block migration to Angular 6 for us, because 13.1.0 version has the same issue with memory leak.

All 4 comments

Any updates on this ticket? It appears to block migration to Angular 6 for us, because 13.1.0 version has the same issue with memory leak.

Same issue using version 11.3.2 and I can't upgrade it now... is there any workaround do clean the memory?

Hello,
Using "observable-profiler" I can detect a lot of observables never completed/unsubscribed.
The "memory leak" that comes a lot is on "OrderableDirective":

    at EventEmitter.subscribe (index.js:44)
    at EventEmitter.subscribe (core.js:35410)
    at subscribe (swimlane-ngx-datatable.js:657)
    at DefaultKeyValueDiffer.forEachAddedItem (core.js:27635)
    at OrderableDirective.updateSubscriptions (swimlane-ngx-datatable.js:672)
    at OrderableDirective.ngAfterContentInit (swimlane-ngx-datatable.js:623)
    at callProviderLifecycles (core.js:32321)
    at callElementProvidersLifecycles (core.js:32293)
    at callLifecycleHooksChildrenFirst (core.js:32275)
    at checkAndUpdateView (core.js:44276)

I have +/- 100 subscriptions added to the stack each time I display the table.
The most "funny" is that I had set [reorderable]= "false" on each column.
Why do I have memory leak on OrderableDirective ? ^^

Was this page helpful?
0 / 5 - 0 ratings

Related issues

IngoManthey picture IngoManthey  路  3Comments

TakhirMamirov picture TakhirMamirov  路  3Comments

JanStock picture JanStock  路  3Comments

ExTheSea picture ExTheSea  路  3Comments

alceucardoso picture alceucardoso  路  3Comments