Angular.js内存泄漏,何时应该开始担心

时间:2014-04-25 09:34:44

标签: javascript jquery angularjs memory-leaks

所以我有一个相当大的应用程序建立在角度,很多嵌套状态,很多指令,数据表和东西。

我们最近决定切换到完整的单页,而不是几个小的单个应用程序部分(说文章,人,仪表板以前都是一个小的单页应用程序),所以我开始处理性能更多。在Chrome中你不会在视觉上注意到一个东西,另一方面我认为它随着时间的推移变慢。

所以我从三个快照技术开始,看看是什么。但我并不完全确定如何制作它。

IMAGE enter image description here

  • 快照大小每个快照的大小加倍(第一个15mb,第二个67mb,第三个120mb),这是否意味着什么?
  • 有很多红色的dom,例如4000个红色的div

现在我觉得那些红色的div,spans和anchors主要是我的错,我正在做一些不那么平常的东西来渲染那些数据表,使用我制作的这个指令,我也觉得有些堆对象的结果是那些dom元素未被正确删除的结果。

这是table指令基本上做的事情

var rows = '<div class="row" ng-repeat="item in items">';

_.each(columns, function(column) {
   // pass cell as a string from $templateCache, instead of having <table-cell type="column.type"> which loaded correct templateUrl depending on what was passed via type attr
   var cellTemplate = $templateCache.get(column.type);
   rows += '<div class="column">' + cellTemplate  + '</div>';
});

rows += '</div>';

// el is from directive link function
el.html(rows);

$compile(el.contents())(scope);

我之所以这样做是因为当我尝试对行和列使用嵌套ng-repeat以及对单元格使用<table-cell>指令时,渲染时间过长,甚至只有大约6列和50行。

所以我认为正在发生的事情是,这个表中的所有div都没有被正确删除,所以每当这个表指令加载时它们就会不断堆叠。

现在即使我处理那个分离的dom树......那么其他所有的东西,我怎么知道我应该尝试和处理哪些,哪些是角度通常的并且不会影响性能?

//在plunker http://plnkr.co/edit/1fZi6mVn2jBIGF0Q2a40?p=preview

上编辑表格指令

2 个答案:

答案 0 :(得分:6)

泄漏实际上是由另一个完全无害的查找指令引起的,该指令在表的标题中使用,除了创建“排序项”数组然后使用ng-repeat打印它之外什么也没做。更糟糕的是< strong>它不是由我在该指令中做的任何事情引起的,而是由 replace: true引起的......上帝知道为什么,我会尝试在plunker上重现它并报告github。

由于只是通过查看堆报告几乎不可能找到应用程序的哪个部分导致它,我继续删除了应用程序的所有其他部分,但我怀疑它是导致它,然后我发现了它不是那个,所以我接着继续阅读所有其他人。

一旦我发现了真正有问题的指令,我就做了同样的事情,不断删除部分代码,直到内部没有任何内容。

然后很明显它是指令的选项之一,然后我发现替换导致了它。

答案 1 :(得分:5)

该指令没有泄露任何东西。我分叉你的plnkr,添加了更多的对象,如果它泄漏,它会引起注意,并添加了一个重新加载表的按钮。它等待一秒钟,然后再次填充它。

节点被删除并重新创建。尝试找到泄漏的步骤是:

  • 开始录制
  • 等待2秒
  • 按按钮
  • 等待10秒
  • 停止录制

正好做了3次(因此你有相同的内存状态),你会看到正在使用相同的内存:

enter image description here

您可以查看分叉的plnkr

在此之后,我只能猜测可能是什么问题。我将根据我发现here的内容给你一些建议。

  • 检查指令,它们通常是原因。 frickingTable似乎没有做任何有害的事情,但其他习俗可能,即使它们不是你的,也只是发生了。
  • 如果正在使用某种“轮询”填充表,请在重新分配之前清空对象。所以,如果你看到分叉的plnkr,你会看到我先将items放到null然后分配。这应该是方式。在plnkr中,我做了它以使其显而易见(表正在重新填充)但是,我发现如果你不清理对象/数组,浏览器往往会以某种方式保留引用。我用.length = 0null对象清理数组,这使得对该对象的所有可能引用都准备好进行GC控制,不会导致任何泄漏。这听起来很傻,但我已经在Angular和Backbone中看到了它,所以它必须是一个浏览器。

如果没有看到更多代码,我真的无法想到其他任何事情。希望这指向你正确的方向,泄漏是令人讨厌的至少。