-
Notifications
You must be signed in to change notification settings - Fork 3.4k
dialog: memory leak when injecting $mdDialog #11493
Description
Bug:
https://codepen.io/kimtuck/pen/yRRbjb
Detailed Reproduction Steps:
- 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
});