我非常绝望地来到你身边 - 已经为此工作了两天。
我们有一个用 Angular JS 构建的单页应用程序。我们在 HTML5 模式下使用 $routeProvider 来实现 SPA 路由。功能明智 - 一切都很好!
我们有一个附加到 body 元素的全局 Controller ,标题中有一个 Controller 用于快速搜索功能,所有其他 Controller 都在一个路由范围内。 Controller 之间共享一些数据,例如 currentUser 对象和包含用户所选语言的字符串值的 ViewRes 对象。
但是,我们注意到 Chrome 服务为我们的页面占用了太多内存。我使用 Chrome Profiles 工具查看发生了什么。我禁用了大部分使用复杂指令的代码,只留下了基础知识。内存消耗降低了很多,但明显还是有。每当我更改页面时,内存都会增加。
在堆快照中,它显示大部分内存被(闭包)和(数组)占用。分离的 DOM 树也很大。请注意,这些快照包含我们应用程序的基本元素(页眉、页脚和轻量级内容)。如果我包括我们复杂的 UI 组件,那么内存会从 14MB 跳到 50MB 再到 140MB……等等。显然,我们会照顾这些指令,但我担心我们的问题是全局性的,而不仅仅是指令设计不当。
当我打开(数组)元素时,我注意到有一堆它们的浅层大小和保留大小为 6172。跟踪该对象的范围总是会导致一些 ng 指令,如 ngShow、ngIf...
正如您从图像中看到的那样,树以“函数()中的缓存”结束。我们使用 Angular 1.3.6。
编辑:这个项目还包括 jQuery。我们使用的是 jQuery 1.8.2,当我切换到 1.11.2 时,在简单页面(简单 ng-repeat 和简单模型)之间切换不再导致内存泄漏(不再有分离的 DOM 元素)。
现在复杂的指令仍然给我太多的分离元素,所以我现在要处理这些,当我找到原因时我会在这里发布结果。
最佳答案
很难说你的具体问题是什么,但 Angular 中内存泄漏的常见地方包括 $interval、$watches 和事件处理程序。这些函数中的每一个都会创建一个不会被清理的闭包,除非您在 Controller 拆卸时明确删除它。
$interval 特别讨厌,因为它会继续运行,直到您关闭浏览器或网页 - 即使用户移动到不同的选项卡或应用程序,它也不会停止运行!
如果您在这些闭包中创建对 DOM 元素的引用,您很快就会开始咀嚼内存,因为这些引用永远不会被释放,并且 DOM 树会随着用户从一个页面移动到另一个页面而分离。
要解决此问题,请确保在 Controller (以及指令的 Controller 或链接函数)中处理 $destroy 事件,并在使用任何间隔、监视或事件处理程序后明确清除。
您可以通过持有对每个 $interval、watch 或事件处理程序的引用并简单地将其作为 $destroy 事件处理程序中的函数调用来实现。
例如:
// eventListener to remove
var eventListener = $scope.$on('eventName', function(){…});
// remove the eventListener when the $destroy event is fired
$scope.$on('$destroy', function(){
// call the value returned from $scope.$on as a function to remove
// the event listener
eventListener();
}
// remove an event listener defined on a DOM node:
var elementEventListener = element.on('eventName', function(){…});
element.on('$destroy', function(){
elementEventListener();
}
// Stop an interval
var stop = $interval(function(){...});
$scope.$on('$destroy', function(){
stop();
}
// Finally, unbind a $watch
var watchFn = $scope.$watch('someValue', function(newVal){…}
$scope.on('$destroy', function(){
watchFn();
}
最后,永远不要在作用域中存储 DOM 元素! (有关原因,请参阅第 2 点 here)。
关于angularjs - Angular JS 单页应用程序中的神秘内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28201192/