8

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

我试图先给你一些应用程序的描述。之后我会发布一些我可以测量的内存统计数据。我使用了三个诊断工具来测量使用的内存:Windows (7) 任务管理器、Firefox about:memory 和 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
    

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

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

我的想法:每个 Ajax 请求都会创建新的范围和 DOM 节点。之后可能会擦除 DOM 节点,但带有数据的范围可能仍会保留在内存中。这是我的内存泄漏的可能情况和原因吗?

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

我会非常高兴任何帮助。

托拜厄斯

4

1 回答 1

3

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

从文档中:

$销毁()

从父作用域中移除当前作用域(及其所有子作用域)。移除意味着对 $digest() 的调用将不再传播到当前作用域及其子作用域。删除还意味着当前范围有资格进行垃圾收集。

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

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

于 2013-10-30T13:30:50.760 回答