JavaScript的精确解释<->DOM 循环引用问题 [英] Precise explanation of JavaScript <-> DOM circular reference issue

查看:27
本文介绍了JavaScript的精确解释<->DOM 循环引用问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

jQuery.data 与原始 expando 属性(您的任意属性)相比的吹捧优势之一可以分配给 DOM 节点)是 jQuery.data 是安全的循环引用,因此免费从内存泄漏".来自 Google 的一篇题为 优化 JavaScript 代码" 的文章有更详细的介绍:><块引用>

Web 应用程序最常见的内存泄漏涉及循环JavaScript 脚本引擎和浏览器的 C++ 之间的引用对象的实现 DOM(例如在 JavaScript 脚本之间引擎和 Internet Explorer 的 COM 基础结构,或在JavaScript 引擎和 Firefox XPCOM 基础架构).

它列出了两个循环引用模式的例子:

  • DOM 元素 →事件处理程序 →关闭范围→DOM

  • DOM 元素 →通过扩展→中介对象DOM 元素

然而,如果一个 DOM 节点和一个 JavaScript 对象之间的引用循环产生了内存泄漏,这是否意味着任何非平凡的事件处理程序(例如 onclick)都会产生这样的泄漏?我不明白事件处理程序如何避免引用循环,因为我认为:

  • DOM 元素引用事件处理程序.

  • 事件处理程序引用 DOM(直接或间接).在任何情况下,几乎不可能避免在任何有趣的事件处理程序中引用 window,除非编写一个从全局队列读取操作的 setInterval 循环.

谁能提供 JavaScript 的准确解释 ↔DOM循环引用问题?我想澄清的事情:

  • 哪些浏览器受到影响?jQuery 源代码中的评论特别提到 IE6-7,但 Google 文章暗示 Firefox 也受到影响.

  • expando 属性和事件处理程序在内存泄漏方面有什么不同吗?还是这两个代码片段都容易受到同一种内存泄漏的影响?

    //创建一个引用其自身元素的 expando.var elem = document.getElementById('foo');elem.myself = elem;//创建一个引用其自身元素的事件处理程序.var elem = document.getElementById('foo');elem.onclick = 函数(){elem.style.display = '无';};

  • 如果页面由于循环引用而泄漏内存,泄漏会持续到整个浏览器应用程序关闭,还是在窗口/选项卡关闭时释放内存?

解决方案

复制这些链接中的所有内容可能不值得,因此我建议您阅读并查看 其他谷歌搜索命中:

javascript、循环引用和内存泄漏

你知道什么可能导致内存泄漏吗?JavaScript?

http://www.ibm.com/developerworks/web/图书馆/wa-memleak/

http://www.ibm.com/developerworks/web/library/wa-sieve/index.html?ca=drs-

http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks

最严重的内存泄漏发生在 IE6 中,其中泄漏是永久性的(即使在您离开受影响的网页之后).其他泄漏通常仅在您在该特定页面上时发生,并在您离开该页面时被清除.

事实是浏览器应该能够处理循环引用.它应该能够看到,即使 DOM 元素仍在被 JavaScript 元素引用,但 JavaScript 元素本身仅存在是因为 DOM 元素仍然存在,因此没有真正的外部引用留给 DOM 元素.正是这种认识是旧版本的 IE 所不擅长的.因此,在涉及事件处理程序的代码引用中,垃圾收集器需要足够聪明,以知道 JavaScript 中对 DOM 元素的唯一引用是引用,当 DOM 元素及其事件处理程序被删除时,这些引用本身就会消失 - 因此没有真正的外部引用,因此删除 DOM 元素和事件处理程序是安全的.这是一般循环引用问题的更复杂版本,所有垃圾收集器都必须处理其中对象 A 引用对象 B 和对象 B 引用对象 A,但没有其他对象引用 A 或 B,因此两者都可以被释放.

jQuery 的 .data() 使事情变得更可靠,因为旧版本的 IE 有一个特殊问题,即添加到 DOM 元素的属性并且没有正确处理循环引用,这些引用中的数据属性,因此在它应该有的时候不会释放东西(泄漏)..data() 通过在 DOM 元素上仅使用一个添加的属性来解决这个问题,该属性是一个安全、无泄漏的字符串.然后,该字符串是 JavaScript 对象的键,该对象可以包含您希望与 DOM 元素关联的所有属性.因为这些属性都存储在纯 JavaScript 中,浏览器没有循环引用错误,所以这样做不会导致泄漏.

重要的是要意识到可能仍然存在一些循环引用,这没关系.解决方法是将循环引用移动到浏览器适当处理它们的地方,而不是将它们放在浏览器有错误的地方.

One of the touted advantages of jQuery.data versus raw expando properties (arbitrary attributes you can assign to DOM nodes) is that jQuery.data is "safe from circular references and therefore free from memory leaks". An article from Google titled "Optimizing JavaScript code" goes into more detail:

The most common memory leaks for web applications involve circular references between the JavaScript script engine and the browsers' C++ objects' implementing the DOM (e.g. between the JavaScript script engine and Internet Explorer's COM infrastructure, or between the JavaScript engine and Firefox XPCOM infrastructure).

It lists two examples of circular reference patterns:

  • DOM element → event handler → closure scope → DOM

  • DOM element → via expando → intermediary object → DOM element

However, if a reference cycle between a DOM node and a JavaScript object produces a memory leak, doesn't this mean that any non-trivial event handler (e.g. onclick) will produce such a leak? I don't see how it's even possible for an event handler to avoid a reference cycle, because the way I see it:

  • The DOM element references the event handler.

  • The event handler references the DOM (either directly or indirectly). In any case, it's almost impossible to avoid referencing window in any interesting event handler, short of writing a setInterval loop that reads actions from a global queue.

Can someone provide a precise explanation of the JavaScript ↔ DOM circular reference problem? Things I'd like clarified:

  • What browsers are effected? A comment in the jQuery source specifically mentions IE6-7, but the Google article suggests Firefox is also affected.

  • Are expando properties and event handlers somehow different concerning memory leaks? Or are both of these code snippets susceptible to the same kind of memory leak?

    // Create an expando that references to its own element.
    var elem = document.getElementById('foo');
    elem.myself = elem;
    
    // Create an event handler that references its own element.
    var elem = document.getElementById('foo');
    elem.onclick = function() {
        elem.style.display = 'none';
    };
    

  • If a page leaks memory due to a circular reference, does the leak persist until the entire browser application is closed, or is the memory freed when the window/tab is closed?

解决方案

It's probably not worth reproducing all the content in these links, so I'd suggest you do some reading and a look at the other Google search hits:

javascript, circular references and memory leaks

Do you know what may cause memory leaks in JavaScript?

http://www.ibm.com/developerworks/web/library/wa-memleak/

http://www.ibm.com/developerworks/web/library/wa-sieve/index.html?ca=drs-

http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks

The worst memory leaks are in IE6 where the leaks are permanent (even after you leave the affected web page). The other leaks are generally only while you're on that specific page and get cleaned up when you leave the page.

The fact is that the browser is supposed to be able to handle circular references. It's supposed to be able to see that even though a DOM element is still being referred to by a JavaScript element, that the JavaScript element itself only exists because the DOM element is still alive and thus there is no true outside reference left to the DOM element. It is this recognition that older versions of IE were bad at. Thus in your code references that involve event handlers, the garbage collector needs to be smart enough to know that the only references left to the DOM element in JavaScript are references that themselves would go away when the DOM element and it's event handlers were removed - thus there are no true outside references so it's safe to remove both the DOM element and the event handler. This is a more complicated version of the general circular reference problem that all garbage collectors have to handle where object A refers to object B and object B refers to object A, but no other object refers to either A or B, thus both can be freed.

jQuery's .data() makes things more reliable because the older versions of IE had a particular problem with properties that were added to a DOM element and did not handle circular references properly involving the data in those properties and thus would not free things when it should have (a leak). .data() works around that by only using one added property on the DOM element which is a safe, non-leaking string. That string is then a key into a JavaScript object that can contain all the properties that you would like to associate with the DOM element. Because these properties are all stored in plain JavaScript, where the browsers don't have the circular reference bugs, doing it this way doesn't cause leaks.

It's important to realize that there may still be some circular references and that's OK. The work-around is to move the circular references to a place that the browsers handle them appropriately rather than putting them in the place that the browsers have bugs.

这篇关于JavaScript的精确解释&lt;-&gt;DOM 循环引用问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆