Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

dialog: memory leak when injecting $mdDialog #11493

Closed
kimtuck opened this issue Oct 23, 2018 · 4 comments · Fixed by #11641
Closed

dialog: memory leak when injecting $mdDialog #11493

kimtuck opened this issue Oct 23, 2018 · 4 comments · Fixed by #11641
Assignees
Labels
has: Pull Request A PR has been created to address this issue P1: urgent Urgent issues that should be addressed in the next minor or patch release. resolution: fixed severity: performance This issue causes a significant performance degradation type: performance This issue is related to performance
Milestone

Comments

@kimtuck
Copy link

kimtuck commented Oct 23, 2018

Bug:

https://codepen.io/kimtuck/pen/yRRbjb

Detailed Reproduction Steps:

  1. Run the contents of the pen using karma. Monitor the memory usage of chrome while the tests are running. You will see the memory creep up dramatically, until around 2.1GB chrome crashes.

What is the expected behavior?

Memory remains more or less constant, because all we're doing here is injecting $mdDialog, which is a service (a singleton).

What is the current behavior?

Memory is dramatically consumed

What is the use-case or motivation for changing an existing behavior?

Memory leak will lead to application crashes or poor performance. In a set of unit tests that inject $mdDialog in many places (as our application does) chrome crashes during the unit test run, leading to a failed unit test.

Which versions of AngularJS, Material, OS, and browsers are affected?

See the package.json in the codepen. Relevant lines from package.json:
"angular": "^1.7.2",
"angular-animate": "^1.7.2",
"angular-aria": "^1.7.2",
"angular-messages": "^1.7.2",
"angular-material": "^1.1.10",

  • OS: windows 10
  • Browsers: Chrome

Is there anything else we should know? Stack Traces, Screenshots, etc.

This is the (partial) code for MdDialogProvider. If you remove the .setDefaults() and the .addPresets() then there is no memory leak. If you include the .setDefaults() and remove the .addPresets() then the memory leak occurs.

So, the memory leak is in the .setDefaults() call.

Note that on each test invocation, the MdDialogProvider method executes; and thus the setDefaults() method runs on each test invocation.

function MdDialogProvider($$interimElementProvider) {
  // Elements to capture and redirect focus when the user presses tab at the dialog boundary.
  MdDialogController['$inject'] = ["$mdDialog", "$mdConstant"];
  dialogDefaultOptions['$inject'] = ["$mdDialog", "$mdAria", "$mdUtil", "$mdConstant", "$animate", "$document", "$window", "$rootElement", "$log", "$injector", "$mdTheming", "$interpolate", "$mdInteraction"];
  var topFocusTrap, bottomFocusTrap;

  return $$interimElementProvider('$mdDialog')
    .setDefaults({
      methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose',
          'targetEvent', 'closeTo', 'openFrom', 'parent', 'fullscreen', 'multiple'],
      options: dialogDefaultOptions
    })
    .addPreset('alert', {
      methods: ['title', 'htmlContent', 'textContent', 'content', 'ariaLabel', 'ok', 'theme',
          'css'],
      options: advancedDialogOptions
    })
    .addPreset('confirm', {
      methods: ['title', 'htmlContent', 'textContent', 'content', 'ariaLabel', 'ok', 'cancel',
          'theme', 'css'],
      options: advancedDialogOptions
    })
    .addPreset('prompt', {
      methods: ['title', 'htmlContent', 'textContent', 'initialValue', 'content', 'placeholder', 'ariaLabel',
          'ok', 'cancel', 'theme', 'css', 'required'],
      options: advancedDialogOptions
    });
@Splaktar Splaktar self-assigned this Oct 25, 2018
@Splaktar Splaktar added type: performance This issue is related to performance severity: performance This issue causes a significant performance degradation P1: urgent Urgent issues that should be addressed in the next minor or patch release. labels Oct 25, 2018
@Splaktar Splaktar changed the title Memory leak when injecting $mdDialog dialog: memory leak when injecting $mdDialog Oct 25, 2018
@Splaktar
Copy link
Contributor

This looks like a duplicate of #11207, but the information on debugging is much appreciated!

@Splaktar Splaktar added the needs: investigation The cause of this issue is not well understood and needs to be investigated by the team or community label Oct 25, 2018
@Splaktar Splaktar added this to the 1.1.12 milestone Oct 25, 2018
@kimtuck
Copy link
Author

kimtuck commented Oct 25, 2018

It's not a duplicate. #11207 involves actually creating, opening, and closing a dialog; this issues involves a case where no dialog is opened; simply injecting the $mdDialog service several times is enough to cause a leak.

@Splaktar
Copy link
Contributor

I only said that it "looks like a duplicate". I didn't say that it was a duplicate and I didn't close it as a duplicate. But thank you for your clarification.

#11024 (comment) also reports a memory leak where md-button is used and $mdDialog is injected but never used. I'll do some re-testing of things after we get one of these fixed to see how it affects the others.

@kimtuck
Copy link
Author

kimtuck commented Dec 31, 2018

I figured out what the root cause of this issue is, and a workaround. The root cause is that the $mdInteraction service registers some listeners on the DOM. In a unit test environment, these are never cleaned up. For example, injecting $mdDialog injects the $mdInteraction service each time; and when $mdInteraction is instantiated for the first time (as it is on any unit test that causes it to be injected) the listeners are registered.

So if you have enough tests that inject $mdDialog, you get enough listeners registered that Chrome's memory grows too large, and chrome crashes.

To avoid this, you can replace the $mdInteraction service with a stub. I've done this, and my memory issues have been fixed.

// The $mdInteraction service causes a memory leak because it registers dom event listeners and does not
// clean them up.  In a unit test environment where the service is re-initialized frequently, these
// event handlers build up and consume memory.
//
// Since, in a unit test environment, there is never any user interaction with the dom anyway,
// it's safe to replace $mdInteraction service with a different service that does not
(function() {
  'use strict';

  angular.module('material.core.interaction').service('$mdInteraction', function() {
  });
})();

In your karma.conf.js, you have an array of files to be included for your tests. Put the above code in a file, and include it after you include angular-material.

@Splaktar Splaktar modified the milestones: 1.1.12, 1.1.13 Jan 3, 2019
@Splaktar Splaktar modified the milestones: 1.1.13, 1.1.14 Feb 10, 2019
@Splaktar Splaktar modified the milestones: 1.1.14, g3: sync Feb 15, 2019
codymikol added a commit to codymikol/material that referenced this issue Feb 19, 2019
this was causing memory leaks when unit testing

Fixes: angular#11493
codymikol added a commit to codymikol/material that referenced this issue Feb 19, 2019
this prevents unit tests from leaking memory

Fixes: angular#11493
codymikol added a commit to codymikol/material that referenced this issue Feb 19, 2019
this prevents unit tests from leaking memory

Fixes: angular#11493
codymikol added a commit to codymikol/material that referenced this issue Feb 19, 2019
this prevents unit tests from leaking memory

Fixes: angular#11493
codymikol added a commit to codymikol/material that referenced this issue Feb 19, 2019
this prevents unit tests from leaking memory

Fixes: angular#11493
@Splaktar Splaktar added has: Pull Request A PR has been created to address this issue and removed needs: Pull Request needs: investigation The cause of this issue is not well understood and needs to be investigated by the team or community labels Feb 26, 2019
@Splaktar Splaktar removed this from the g3: sync milestone Feb 26, 2019
@Splaktar Splaktar added this to the 1.1.14 milestone Feb 26, 2019
codymikol added a commit to codymikol/material that referenced this issue Feb 28, 2019
this prevents unit tests from leaking memory

Fixes angular#11493
mmalerba pushed a commit that referenced this issue Mar 14, 2019
this prevents unit tests from leaking memory

Fixes: #11493

<!-- 
Filling out this template is required! Do not delete it when submitting a Pull Request! Without this information, your Pull Request may be auto-closed.
-->
## PR Checklist
Please check that your PR fulfills the following requirements:
- [x] The commit message follows [our guidelines](https://github.com/angular/material/blob/master/.github/CONTRIBUTING.md#-commit-message-format)
- [ ] Tests for the changes have been added or this is not a bug fix / enhancement
- [ ] Docs have been added, updated, or were not required

## PR Type
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
```
[x] Bugfix
[ ] Enhancement
[ ] Documentation content changes
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Infrastructure changes
[ ] Other... Please describe:
```

## What is the current behavior?

Currently the $mdInteraction service registers when invoked. This causes a memory leak in unit tests because nothing is in place to clean up the events.

<!-- Please describe the current behavior that you are modifying and link to one or more relevant issues. -->
Issue Number: #11493

## What is the new behavior?

Now on the $destroy event of rootScope the events registered will be unregistered.

## Does this PR introduce a breaking change?
```
[ ] Yes
[x] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
<!-- Note that breaking changes are highly unlikely to get merged to master unless the validation is clear and the use case is critical. -->

## Other information
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has: Pull Request A PR has been created to address this issue P1: urgent Urgent issues that should be addressed in the next minor or patch release. resolution: fixed severity: performance This issue causes a significant performance degradation type: performance This issue is related to performance
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants