我想了解什么样的代码会导致内存泄漏的JavaScript和创建下面的脚本。 然而,当我在Safari中运行该脚本在OS X 6.0.4在活动监视器并没有真正增加显示的内存消耗。
什么毛病我的脚本,或者这是不再与现代的浏览器的问题吗?
<html>
<body>
</body>
<script>
var i, el;
function attachAlert(element) {
element.onclick = function() { alert(element.innerHTML); };
}
for (i = 0; i < 1000000; i++) {
el = document.createElement('div');
el.innerHTML = i;
attachAlert(el);
}
</script>
</html>
剧本是基于谷歌的JavaScript风格指南的合龙段: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures
编辑:导致上述代码泄漏的错误明显地被固定: http://jibbering.com/faq/notes/closures/#clMem
但我的问题是:会有人能够提供在现代浏览器中出现内存泄漏的JavaScript代码现实的例子?
有在互联网上暗示内存泄漏可以为复杂的单页的应用程序的问题,很多文章,但我有一个很难找到的,我可以在我的浏览器中运行的实例。
你不是让你已经创建了周围,任何地点引用的元素 - 这就是为什么你没有看到内存使用率增加。 尝试的元件附接至所述DOM,或将其存储在一个对象,或者设置的onclick到是支左右不同的元件。 然后你就会看到内存使用扶摇直上。 垃圾收集器会通过,并清理任何可以不再被引用。
基本上你的代码的演练:
- 创建元件(EL)
- 创建一个新的功能,它引用该元素
- 设置的功能到是元件的onclick
- 新元素覆盖的元素
一切都是存在的元素围绕中心。 一旦没有访问该元素的方式,的onclick不能再访问。 所以,既然的onclick不能被访问,已创建的功能被破坏..和功能必须的元素仅供参考..这样的元素被清理为好。
有人可能有更多的技术例子,但是这是我的JavaScript垃圾收集器的理解的基础上。
编辑:这里是您的脚本的泄漏版本的许多可能性之一:
<html>
<body>
</body>
<script>
var i, el;
var createdElements = {};
var events = [];
function attachAlert(element) {
element.onclick = function() { alert(element.innerHTML); };
}
function reallyBadAttachAlert(element) {
return function() { alert(element.innerHTML); };
}
for (i = 0; i < 1000000; i++) {
el = document.createElement('div');
el.innerHTML = i;
/** posibility one: you're storing the element somewhere **/
attachAlert(el);
createdElements['div' + i] = el;
/** posibility two: you're storing the callbacks somewhere **/
event = reallyBadAttachAlert(el);
events.push(event);
el.onclick = event;
}
</script>
</html>
所以,对#1,你只是储存于元素的引用的地方。 不要紧,你永远不会使用它 - 因为引用的对象所做的元素及其回调永远不会消失(或者至少直到您删除对象的元素)。 对于可能性#2,你可以在某个地方存储的事件。 由于事件可以被访问(通过这样做,即events[10]();
),即使元素是无处可寻,它仍然在事件中引用..这样的元素会保留在内存中,以及事件,直到它是从数组中删除。
更新:这是基于谷歌I / O呈现缓存场景很简单的例子:
/*
This is an example of a memory leak. A new property is added to the cache
object 10 times/second. The value of performance.memory.usedJSHeapSize
steadily increases.
Since the value of cache[key] is easy to recalculate, we might want to free
that memory if it becomes low. However, there is no way to do that...
Another method to manually clear the cache could be added, but manually
adding memory checks adds a lot of extra code and overhead. It would be
nice if we could clear the cache automatically only when memory became low.
Thus the solution presented at Google I/O!
*/
(function(w){
var cache = {}
function getCachedThing(key) {
if(!(key in cache)) {
cache[key] = key;
}
return cache[key];
}
var i = 0;
setInterval(function() {
getCachedThing(i++);
}, 100);
w.getCachedThing = getCachedThing
})(window);
因为当页面从本地文件系统打开usedJSHeapSize不更新 ,你可能看不到增加的内存使用情况。 在这种情况下,我在这里主办了你这样的代码: https://memory-leak.surge.sh/example-for-waterfr
这谷歌I / O'19表现给出了避免他们真实世界的内存泄漏的例子以及策略:
- 方法
getImageCached()
返回一个引用到一个对象,也缓存本地参考。 即使这个引用超出方法消费者的范围,被引用的内存不能被垃圾收集,因为后面还有一个里面执行很强的借鉴意义getImageCached()
理想情况下,如果内存有太多低缓存参考将有资格进行垃圾回收。 (不完全是内存泄漏,但那里是内存,可以运行在昂贵的运营成本再次被释放的情况下)。 - 泄漏#1:参照缓存的图像。 通过使用内弱引用解决
getImageCached()
- 泄漏#2:缓存(Map对象)内的字符串键。 通过使用新的解决
FinalizationGroup
API。
请参阅JS代码行由行说明链接的视频。
更一般地,“真正的” JS内存泄漏是由不必要的引用引起的(到再也不会被使用的对象)。 他们通常是在JS代码中的bug。 本文介绍了四种常见方式内存泄漏在JS介绍 :
- 意外的全局变量
- 忘记的定时器/回调
- 走出DOM参考
- 关闭
一个有趣的一种JavaScript的内存泄漏的文件关闭怎么造成的流行MeteorJS框架内存泄漏。
如果你想要的是创建一个内存泄漏,那么IMO最简单的方法就是实例化一个TypedArray ,因为他们抢去了固定的内存大小而存在的任何引用。 例如,创建一个Float64Array
与2^27
的元件消耗1GiB( 1 Gibibyte的存储器),因为它需要每个单元的8个字节 。
启动控制台,只是这样写:
new Float64Array(Math.po2(2, 27))
我试图做这样的事情,得到了异常的内存不足。
const test = (array) => {
array.push((new Array(1000000)).fill('test'));
};
const testArray = [];
for(let i = 0; i <= 1000; i++) {
test(testArray);
}