我在Chrome开发者工具中描述了我的网络应用程序,并提出了上面显示的时间表。我正在创建和删除悬停功能中的元素。我已在this article中了解到这一点。
这种模式表明我有内存泄漏吗?节点计数(绿线)不断上升,而不是在内部GC上下降。但我的强制GC降至零。这是常见的行为吗?
我的意思是,它在内存中保存了很多节点,即使它们不存在。如果我检查堆,则不存在对DOM节点的引用(没有分离的DOM等),这让我觉得这不是内存泄漏?
你的五美分是多少?
以下代码:
$(document).on("mouseenter", ".btn", function(e){
var el = document.createElement("div");
el.id = "box";
document.body.appendChild(el);
});
$(document).on("mouseleave", ".btn", function(e){
$("#box").remove();
});
答案 0 :(得分:3)
我在Chrome中显示的跟踪中没有看到内存泄漏。您缺少的信息是当垃圾收集周期开始时,周期可能部分收集垃圾。让我解释一下。
我不熟悉v8中的垃圾收集器,但在过去的不同时间,我一直在垃圾收集器上工作。垃圾收集是在快速释放未使用的内存和应用程序响应之间的平衡行为。特别是在交互式应用程序中,您不希望长时间暂停执行以允许完整的垃圾收集周期,因为这会影响用户的体验。因此存在一些策略,即垃圾收集周期可以部分而不是完成。似乎v8使用了这样的策略,因为Google's blurb on v8's garbage collection表示:
这意味着V8:
- 在执行垃圾回收循环时停止程序执行。
- 在大多数垃圾收集周期中仅处理对象堆的一部分。这可以最大限度地减少停止应用程序的影响。
所以你不应该指望大多数周期都会将节点数减少到零。
为什么强制GC将计数降为零?通过谷歌关于调试内存泄漏的文档推断,我推断强迫GC循环不仅强制GC循环的开始,而且强制循环完成而不是部分,否则强制循环将是对于想知道是否存在内存泄漏的人来说没用。
答案 1 :(得分:2)
好的,让我们试着面对这个问题。
<强>可能性:强>
Javascript内存管理如何工作?它完全取决于可达性:
- 假设一组杰出的对象可以访问:这些是 被称为根。通常,这些包括所有对象 从调用堆栈中的任何位置引用(即,所有本地 当前正在调用的函数中的变量和参数), 和任何全局变量。
- 对象保存在内存中 可通过参考或参考链从根本访问。
醇>
http://javascript.info/tutorial/memory-leaks
基本上,JS会在内存无法访问时将其从内存中删除。让我们试一试:
<强> HTML:强>
<html>
<div class="ourDiv"></div>
</html>
<强> JS:强>
$(".ourDiv").append(document.createElement("span"))
.remove();
在这个例子中,我故意使用类而不是ID,你会明白为什么。我们的记忆看起来像这样:
让我们将其修改为与您的代码更相似:
JS:
var newEl=document.createElement("span");
newEl.id = "ourSpan";
$(".ourDiv").append(newEl)
.remove();
现在怎么样?
元素#id是一个例外。它可以作为#ourSpan访问,所以它 留在记忆中。当然,如果你检查它的parentNode,它会是 空。
<强>结论:强>
当您为每个创建的元素设置ID时,即使您尝试使用jQuery调用删除它们,javascript也会将其存储在内存中。可能是因为将创建元素与本机API混合并在jQuery中删除它。尝试检查$.cache
大小 - 如果它太大,则表示jQuery没有正确删除对象。
但首先 - 避免在不断创建的元素中使用ID应该会有所帮助。
中有更多解释答案 2 :(得分:0)
对此不是100%肯定,但我认为问题可能是你的mouseenter / mouseleave事件没有解除绑定?