内存泄露问题
这是我在其他地方看到的一道题:
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
var unused = function () {
if (originalThing) // 'originalThing'的引用
console.log("嘿嘿嘿");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: function () {
console.log("哈哈哈");
}
};
};
setInterval(replaceThing, 1000);
对于这段代码,老师的解释是:
要想揪出其中的问题,大家需要对 V8 引擎有所了解,尤其是这一点:在 V8 中,一旦不同的作用域位于同一个父级作用域下,那么它们会共享这个父级作用域。
在这段代码里, unused 是一个不会被使用的闭包,但和它共享同一个父级作用域的 someMethod,则是一个 “可抵达”(也就意味着可以被使用)的闭包。unused 引用了 originalThing,这导致和它共享作用域的 someMethod 也间接地引用了 originalThing。结果就是 someMethod “被迫” 产生了对 originalThing 的持续引用,originalThing 虽然没有任何意义和作用,却永远不会被回收。不仅如此,originalThing 每次 setInterval 都会改变一次指向(指向最近一次的 theThing 赋值结果),这导致无法被回收的无用 originalThing 越堆积越多,最终导致严重的内存泄漏。
我在控制台运行了一下这段代码,结果是 输出了 179921,不理解啊。
我有以下几点疑问:
1、为什么这段代码执行完,会输出一个数呢?这个数怎么得到的呢?
2、unused为什么和someMethod是共享同一个父级作用域的?someMethod不是theThing 的值的一部分吗?
3、为什么,unused 引用了originalThing,和它共享作用域的someMethod也间接地引用了originalThing?
4、这段代码里的函数都没有被执行呀,那里面的函数不就都是不会被使用的吗?
5、每次 setInterval之后,originalThing 都会指向最近一次的 theThing 赋值结果,originalThing
不是只是改变了指向吗,它还是只有一个啊,怎么会导致无用的originalThing 越堆积越多呢?
正在回答
同学你好,对于你的问题解答如下:
老师测试同学粘贴的代码,控制台没有打印任何内容,同学再测试下
因为ES5中只有全局作用域和函数作用域,对象的{}不是一个作用域。unused和someMethod都处于replaceThing函数作用域下,所以说unused和someMethod是共享一个父级作用域
因为闭包unused中引用了originalThing,导致originalThing变量一直保存在内存中,是共享的,那么在replaceThing函数中定义的闭包方法,都可以使用originalThing这个变量,所以说someMethod也间接的引用了originalThing
这段代码中的,只有replaceThing函数每隔一秒调用一次,在执行replaceThing方法时,内部定义的theThing对象下的longStr属性对应的new Array(1000000).join('*')会被执行。
但是unused和someMethod方法没有被执行。
定时器每隔一秒钟,就会调用一次replaceThing方法,theThing都会被重新赋值,产生一个someMethod闭包, originalThing指向最近一次的theThing,确实只改变了指向,但是由第三条分析可知,someMethod中间接引用了originalThing,所以就算theThing重新赋值了,它的上一次值并不会被回收,导致越堆积越多。
本站的教学服务只包含站内视频内容问题解答、站内习题问题解答、站内作业问题解答、站内测试题问题解答以及站内产品使用问题解答。同学的问题是在其他地方看到的题,与本站视频、习题以及作业等内容无关联,故不包含在本站的教学服务内。但是看同学比较爱学习,所以老师这次破例为你讲解。
老师这里给同学一个小小的建议,在其他地方看到代码存在疑问,推荐同学跟发帖的人直接交流沟通,这样获取的信息更加直观准确。
祝学习愉快~
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星