Javascript 解释Addy Osmani在smashing magazine中的闭合内存泄漏示例
我在《粉碎》杂志的结尾部分读到了艾迪·奥斯马尼的博客。我理解以下函数包含对Largester的引用,GC不能声明它Javascript 解释Addy Osmani在smashing magazine中的闭合内存泄漏示例,javascript,performance,garbage-collection,Javascript,Performance,Garbage Collection,我在《粉碎》杂志的结尾部分读到了艾迪·奥斯马尼的博客。我理解以下函数包含对Largester的引用,GC不能声明它 var a = function () { var largeStr = new Array(1000000).join('x'); return function () { return largeStr; }; }(); 他在这里提到的解决方案没有提到Largester,GC可以声称它。相反,他使用smallStr var a = functio
var a = function () {
var largeStr = new Array(1000000).join('x');
return function () {
return largeStr;
};
}();
他在这里提到的解决方案没有提到Largester,GC可以声称它。相反,他使用smallStr
var a = function () {
var smallStr = 'x';
var largeStr = new Array(1000000).join('x');
return function (n) {
return smallStr;
};
}();
我明白了艾迪的意思,他没有提到一件大事。但是,我想知道有没有更好的方法,我可以拥有第一个函数的功能,并使其内存效率更高。第一个函数创建的
最大的并返回引用它的函数。因此,合乎逻辑的是,垃圾收集器无法释放largester
,因为现在包含在a
变量中的函数仍在使用它
第二个函数没有对最大值的持久引用,因此垃圾收集器可以释放它
听起来你在问是否有一种方法可以保留对某个大对象的引用,但不使用该内存。答案是否定的
此外,从技术上讲,这些根本不是“泄漏”。它们是合法的内存使用
通过不预构建大字符串,可以在不占用内存的情况下实现第一个函数的功能。如果您根据需要构建它,那么在有人调用该函数之前,它不会消耗内存。这显然是执行速度和内存使用之间的直接折衷,但这是您在这里得到的选择。如果它是预缓存的,那么它会消耗内存。如果它只是根据需要构建的,那么它在使用之前不会消耗内存
以下是按需构建的版本,在使用之前不会消耗内存:
var a = function () {
return function () {
return new Array(1000000).join('x');
};
}();
不必写得这么迟钝。也可以是这样,因为不涉及关闭:
var a = function() {
return new Array(1000000).join('x');
}
这两个版本的缺点是每次调用a()
时都会创建字符串,但优点是不会永久缓存任何内容。当a()
的所有使用都完成时,所有内容都会被垃圾收集
或者,仅在首次使用时对其进行缓存:
var a = function () {
var largeStr;
return function () {
if (!largeStr) {
largeStr = new Array(1000000).join('x');
}
return largeStr;
};
}();
这样做的好处是,在第一次调用a()
之前不会消耗内存,对a()
的后续调用不必重新创建大字符串,但创建后,将永远不会对单个最大字符串进行垃圾收集
哪一种最好取决于您的使用模式,哪一种权衡在您的设计/使用中更为重要。您需要经过深思熟虑的设置才能导致V8 Close内存泄漏:
function create() {
var a = "x";
var b = new Array(1000000).join('x');
//Force context-allocation for b
(function(){b;});
return function() {
return a;
};
}
window.a = create();
b
无法被代码访问,但在您完全摆脱窗口之前,它无法被收集。a
:
如果您在chrome中使用堆快照,您将看到。本文并不打算暗示这两个函数做相同的事情。它们只是例子。但我想,您可以将创建大字符串的代码移动到返回的函数中。但每次都会产生一个新的张力。一次又一次地产生相同的张力不是一个好主意。一个全局将更好(节省处理时间)。。。实际上,我在解释这个问题,想知道什么是最好的解决方案。这取决于字符串发生了什么。如果代码很少需要字符串,而且只需要很短的时间,那么最好每次都创建一个新副本。如果代码经常需要它,那么第一个版本可能还可以(而且比全局变量更好)。我想知道我是否遗漏了一些方面。谢谢你的回答。