加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

angularjs – Angular JS单页应用程序中的神秘内存泄漏

发布时间:2020-12-17 17:53:30 所属栏目:安全 来源:网络整理
导读:我非常绝望地来找你 – 现在已经为此工作了两天. 我们有一个使用Angular JS构建的单页面应用程序.我们在HTML5模式下使用$routeProvider来实现SPA路由.功能明智 – 一切都很棒! 我们有一个连接到body元素的全局控制器,标题中有一个控制器用于快速搜索功能,所
我非常绝望地来找你 – 现在已经为此工作了两天.

我们有一个使用Angular JS构建的单页面应用程序.我们在HTML5模式下使用$routeProvider来实现SPA路由.功能明智 – 一切都很棒!

我们有一个连接到body元素的全局控制器,标题中有一个控制器用于快速搜索功能,所有其他控制器都作用于路径.控制器之间共享一些数据,如currentUser对象和包含用户所选语言的字符串值的ViewRes对象.

但是,我们注意到Chrome服务为我们的页面占用了太多内存.我使用Chrome Profiles工具查看发生了什么.我禁用了大多数使用复杂指令的代码,只省略了基础知识.内存消耗降低了很多,但显然仍然存在.每当我更改页面时,内存都会增加.

在堆快照中,它显示大多数内存由(闭包)和(数组)占用.分离的DOM树也很大.请注意,这些快照包含我们应用程序的基本元素(页眉,页脚和轻量级内容).如果我包含我们复杂的UI组件,那么内存从14MB跳到50MB到140MB ……等等.显然我们会照顾这些指令,但我担心我们的问题是全局性的,而不仅仅是对指令的错误设计.

当我打开(数组)元素时,我注意到它们中有一堆具有浅的大小和保留的大小6172.跟踪该对象的范围总是导致一些ng指令,如ngShow,ngIf …

从图像中可以看出,树在’cache in function()’中结束.我们使用Angular 1.3.6.

编辑:这个项目还包括jQuery.我们使用的是jQuery 1.8.2,当我切换到1.11.2时,在简单页面(简单的ng-repeats和简单模型)之间切换不再导致内存泄漏(不再有分离的DOM元素).

现在复杂的指令仍然给了我太多的分离元素,所以我现在要处理那些,当我找到原因时我会在这里发布结果.

解决方法

很难说出你的具体问题是什么,但Angular内存泄漏的常见地方包括$interval,$watches和事件处理程序.除非您在控制器拆除时明确删除它,否则这些函数中的每一个都会创建一个未清除的闭包.

$interval特别令人讨厌,因为它会继续运行,直到你关闭浏览器或网页 – 即使用户移动到不同的选项卡或应用程序,它也不会停止运行!

如果在这些闭包中创建对DOM元素的引用,您很快就会开始咀嚼内存,因为从不会释放引用,并且当用户从一个页面移动到另一个页面时,DOM树会分离.

要解决此问题,请确保在控制器(以及指令的控制器或链接函数)中处理$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点的原因).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读