AngularJS:如何正确使用指令,范围和绑定以避免内存泄漏?

fea*_*e86 8 data-binding angularjs angularjs-directive angularjs-scope

我正在尝试为AngularJS app内存泄漏找到解决方案.因为我是AngularJS世界的新手,所以我真的不知道从哪里开始以及在哪里纠正和优化我的代码.

我想先给你一些关于应用程序的描述.之后我会发布一些我可以衡量的记忆统计数据.我使用了三种诊断工具来测量已用内存:Windows(7)任务管理器,Firefox关于:内存和Firefox扩展MemChaser.

应用

  • 应用程序嵌入在页面中,应该加载一次并在那里停留至少24小时
  • 数据通过$ http() Ajax请求以1到60分钟的间隔连续加载
  • 数据是具有某种层次结构的JSON对象
  • 对于此层次结构的每个层,都有一个自定义组件(具有隔离范围)
  • 选定的数据部分将被注意到并保持在Ajax请求之外
  • 大多数指令加载一个html文件(通过$ http())来编译它作为模板

统计

  • Windows任务管理器

    Firefox使用的内存每小时增加50-100 MB.

  • 约:内存

                                       Size (MB)   20 min diff  Size (MB)
    JS-Main-Runtime                     32         36/+113%      68
    JS-Main-Runtime-GC-Heap-Committed   20         27/+135%      47
    Heap-Allocated                      54         29/+54%       83
    Heap-Committed                      63         28/+44%       91
    JS-GC-Heap                          31         26/+84%       57
    Private                            156         58/+37%      214
    Resident                           175         62/+35%      237
    VSize                              509         86/+17%      595
    
    Run Code Online (Sandbox Code Playgroud)
  • MemChaser 0.5.2.1

                   12:17   12:27   12:57   13:17
    Resident (MB)  140     164     243     270     
    iGC (ms)        42      24      40      42
    CC (ms)          3      53     206     286
    
    Run Code Online (Sandbox Code Playgroud)

    驻留:物理内存中存在的进程使用的内存. iGC:最后一次垃圾收集器活动的持续时间. CC:最后一个循环收集器活动的持续时间.

这些结果非常引人注目,似乎循环收集器给出了最好的提示.如果我在没有视图的情况下运行我的应用程序(只是Ajax请求),则不会发生任 如果我禁用动态模板加载,则动态模板的版本没有明显差异.所以似乎这两个主题不是原因.

我的想法:每个Ajax请求都会创建新的作用域和DOM节点.之后可以建立DOM节点,但是具有数据的范围将可能仍然在存储器中.这可能是我的内存泄漏的原因吗?

那么我应该如何正确使用AngularJS指令,作用域和绑定来避免像这样的内存泄漏?

任何帮助我都会非常高兴.

托比亚斯

Bey*_*ers 3

我使用AngularJS Batarang Chrome 扩展来帮助调试此类问题。监视此扩展的“模型”和“性能”选项卡,以发现任何悬空或泄漏的范围。确保当您不再需要特定范围时,您的$destroy它。例如,看看ngRepeat 如何做到这一点

从文档中:

$销毁()

从父作用域中删除当前作用域(及其所有子作用域)。删除意味着对 $digest() 的调用将不再传播到当前作用域及其子作用域。删除还意味着当前作用域符合垃圾回收条件。

$destroy() 通常由 ngRepeat 等指令使用来管理循环的展开。就在作用域被销毁之前,会在此作用域上广播 $destroy 事件。
应用程序代码可以注册一个 $destroy 事件处理程序,这将使其有机会执行任何必要的清理。请注意,在 AngularJS 中,还有一个 $destroy jQuery 事件,可用于在从 DOM 中删除元素之前清理 DOM 绑定。

当希望作用域及其子作用域与父作用域永久分离,从而通过调用停止参与模型更改检测和侦听器通知时,必须在作用域上调用 $destroy() 。