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

时间:2013-10-30 12:43:26

标签: angularjs data-binding angularjs-directive angularjs-scope

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

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

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

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

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

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

我对任何帮助都非常高兴。

托拜厄斯

1 个答案:

答案 0 :(得分:3)

我使用AngularJS Batarang Chrome扩展程序来协助调试这些类型的问题。监控此扩展的模型和性能选项卡,以了解任何悬空或泄漏范围。确保当您不再需要特定范围时$destroy它。例如。看看如何ngRepeat does this

来自文档:

  

$破坏()

     

从父级移除当前范围(及其所有子级)   范围。删除意味着不再调用$ digest()   传播到当前范围及其子级。删除也意味着   当前范围符合垃圾收集条件。

     

$ destroy()通常由诸如ngRepeat for之类的指令使用   管理循环的展开。就在范围之前   在这个范围内,广播了一个$ destroy事件   应用程序代码可以注册将提供的$ destroy事件处理程序   它有机会进行任何必要的清理工作。请注意,在   AngularJS,还有一个$ destroy jQuery事件,可以用来   在从DOM中删除元素之前清理DOM绑定。

  当需要范围时,必须在范围上调用

$ destroy()   并且它的子范围永久地与父母分离   因此停止参与模型变化检测和监听   通过调用通知。