Javascript内存泄漏:为什么将对象分配给null会起作用
Javascript memory leaks: why would assigning object to null work?
有人能为我挠痒痒吗?关于用于防止内存泄漏的null修复赋值的性质?
我们都熟悉以下技术来停止DOM对象和JS对象之间的循环引用,以防止内存泄漏:
function foo() {
var ele = document.getElementById("someParagraphId");
ele.onclick = function() {
//some action here
};
ele = null;
}
问题是,为什么上述方法会奏效?将"ele"设置为null肯定会停止循环引用,但这不是也会阻止将来对"ele"的引用吗?
function foo() {
var ele = document.getElementById("someParagraphId");
ele.onclick = function() {
console.log("accessing ele ... after set to null " + ele.onclick);
};
ele = null;
}
然而事件侦听器却启动了。它会抱怨"ele"对象为null(这正是我们所期望的)。
考虑到上述行为,我们是否可以推断Javascript引擎实现将持有对事件侦听器的某种内部引用,并且在触发事件时调用的正是这种引用?
eventHandlerRef = //assignment to "ele.onclick" handler/listener;
如果有像上面这样的引用,那么对null fix的赋值不是依赖于实现吗?或者,它是ECMAScript规范的一部分吗。
据我所知,这个修复程序一直是跨浏览器安全的。我没有遇到过很多具体提到在应用null赋值之前检测/嗅探浏览器类型的例子。
================编辑================
我想,由于我提出这个问题的方式,我可能无意中直接从我试图传达的内容中引发了讨论。引用的几个概念:
对象句柄/对象引用ala:
var obj1, obj2;
obj1 = {foo: "bar"}; //obj1 points to the an area of the heap allocated
//for the object literal.
obj2 = obj1; //obj2 points to the same position in the heap
//as obj1.
//obj1 = null or
obj1 = {/*another obj literal*/} //the new object literal is created
//and allocated in some other part
//in the heap, and obj1 now points
//to the new location.
//obj2 is unaffected by obj1's re-assignment.
以上并不是我的痛处,我很后悔加了一行:
console.log("accessing ele ... after set to null " + ele.onclick);
以上内容使这看起来像是一个结束问题。我完全预料到错误会像原来的帖子中所说的那样抛出。
我的瘙痒更多的是。。。出于某种原因,在我看来,Javascript引擎会在事件触发时直接调用ele.onlick()
,将元素设置为null类似于以下流程:
var obj = {};
obj.method = function() {};
obj = null;
//error calling obj.method(), i.e., obj is null
假设我们在最初的帖子中知道,在ele设置为null后,事件处理程序仍然会触发,在我看来,流程更类似于:
var obj = {};
obj.method = function() {};
var objRef = obj;
obj = null;
//The Javascript Engine calling objRef.method when event triggered.
我的问题归结为,上面是大多数Javascript实现的工作方式吗?其中一些内部引用指向指定的事件处理程序,而当事件被触发时,这个内部引用是被调用的吗?
换句话说,是什么阻止Javascript引擎实现直接调用和ele.onclick()
(暂时不考虑设计和体系结构问题)?
也许我的思维过程工作方式不同,但当其他人第一次遇到null fix的赋值时,他们没有再看一眼吗?在这里,元素引用是null ed,但处理程序的代码仍然在执行?
丢弃所有旧答案,并处理编辑:)
让我们举一个更简单的例子:textContent
。
var ele = document.getElementById('foo');
ele.textContent = 'abc';
ele = null;
此代码将#foo
的textContent
设置为abc
,并放弃对ele
的引用。现在,如果我再次请求#foo
,会发生什么?。。。
var ele = document.getElementById('foo');
ele.textContent = 'abc';
ele = null;
ele = document.getElementById('foo');
console.log('#foo is ' + ele.textContent);
它将记录"#foo is abc"
。这只是表明#foo
存在于我的脚本之外,并且document
保留了对它的引用(因为我在document
上调用了一个方法)。它与事件处理程序的工作原理相同。
var ele = document.getElementById('foo');
ele.onclick = function() { console.log('abc'); };
ele = null;
ele = document.getElementById('foo');
console.log('#foo.onclick is ' + ele.onclick);
事件处理程序不是一种特殊的属性。它们只是变量,您可以在上面编写(对函数的)引用。这些大致是函数语言特性,其中函数可以用作简单值。JavaScript实现只是从DOM引用而不是ele
引用调用事件处理程序。让我们再举一个简单的例子,不使用document.getElementById
。
var a = {};
var b = a;
b.foo = function() { console.log("hello world!"); };
console.log(a.foo + " is the same as " + b.foo);
b = null;
console.log("Even though b is " + b + ", a.foo is still " + a.foo);
a.foo();
正如你所看到的,函数并没有绑定到我们分配它们的引用:它们绑定到引用指向的对象。你可以从对对象的任何引用中调用它们,而不仅仅是从你用来分配函数的引用中调用。
因此,您可以在不影响对象正确行为的情况下取消引用以打破循环依赖关系。
我远非JavaScript大师;但我认为,只要提醒变量和对象之间的区别,我至少可以部分回答您的问题。让我们一次一行地遍历您的代码。
var ele = document.getElementById("someParagraphId");
我们在这里做两件事:
- 声明变量(
ele
) - 将对DOM元素(对象)的引用分配给该变量
下一篇:
ele.onclick = function() {
console.log("accessing ele ... after set to null " + ele.onclick);
};
在这里,我们使用变量ele
为其引用的对象(同样是DOM元素)的onclick
事件分配回调。
最后:
ele = null;
最后,我们为ele
变量分配了一个null
引用。它不再引用刚才所做的对象但是,该对象仍然存在,具有相同的onclick
处理程序;它没有改变
处理程序仍然被调用的事实是正确的行为。现在,关于这个错误,让我们再看一下分配给该DOM元素的onclick
事件的函数:
console.log("accessing ele ... after set to null " + ele.onclick);
这个ele
与我们刚刚分配给null
的变量完全相同。因此,当调用此函数时——同样,因为连接到对象的onclick
处理程序没有消失——会引发null引用异常。
由于首先通过调用document.getElementById("someParagraphId")
获得ele
,因此在分配ele
之前,它引用的对象已经存在于内存中。它是文档的一部分——当然,除了ele
之外,内存中还有对它的引用。
- 如何将HTML id分配给元素,以及如何将JavaScript应用于元素
- 在循环中分配json值时,值被覆盖
- 动态分配GA增强型电子商务跟踪器
- 数组在递归方法中设置为null
- 将jsp文件下拉列表中的选定项分配给一个java变量(比如String selection)
- 如何在jQuery中将函数的输出分配给变量
- 为集合分配大量的模型弹药
- 字符串在将其传递给另一个活动Android JavaScript时读取Null
- 无法获取属性'selectedIndex'的未定义引用或null引用
- Meteor方法在客户端返回null,在客户端运行的相同方法返回正确的值
- onclick函数需要双击,因为类分配延迟
- 来自文本输入null的html javascript变量
- delete在Object上效率低下,但在DOM Element's的数据属性,与null out相比
- Javascript 将变量分配给警报
- php代码在textbox更改事件上显示null
- 相同的RegExp返回不同的结果-第一次是正确的结果,第二次是null
- 将节点数据分配给另一个变量jstree
- 在php中提交数据时,如果某些值为null,而某些值为非null,如何进行查询
- 为什么typeof(null)返回“;对象”;,但是你可以't为其分配属性
- 使用数组元素分配“id=”值返回:TypeError:document.getElementById(..)为null