JavaScript:2011 年我应该担心内存泄漏吗?

发布于 2024-12-04 13:18:21 字数 324 浏览 0 评论 0原文

JavaScript 中的内存泄漏这个话题并不经常被提及。然而,我偶然发现了这篇文章,写于 2007 年。作者状态:

Internet Explorer 和 Mozilla Firefox 是最常用的两种 Web 浏览器 通常与 JavaScript 中的内存泄漏相关。

2011 年我还应该担心 JavaScript 内存泄漏吗?如果是这样,我应该注意什么?

The topic of memory leaks in JavaScript is not brought up often. However, I stumbled upon this article, written in 2007. The authors state:

Internet Explorer and Mozilla Firefox are the two Web browsers most
commonly associated with memory leaks in JavaScript.

Should I still be worrying about JavaScript memory leaks in 2011? If so, what should I be careful about?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

命比纸薄 2024-12-11 13:18:21

优秀的 JavaScript 开发人员会意识到可能导致内存泄漏的各种设计模式,并且您会避免在几乎所有编码的页面中编写可能导致泄漏的任何内容。

例如,在 javascript 变量中保留对任何 DOM 对象的引用将使该 DOM 对象在内存中保持活动状态,即使它早已从 DOM 中删除并且您打算释放它。

实际上,泄漏仅在某些情况下才显着。这是我特别担心的地方:

  1. 我在计时器上重复做的任何事情,特别是如果它可以长时间运行的话。例如,如果您有一个可能会永远循环的幻灯片,则必须绝对确保幻灯片中没有任何内容是 JS 或 DOM 对象的累积泄漏。
  2. 一个像应用程序一样工作的网页,用户可能会长时间停留在同一页面上,与页面交互,执行 ajax 调用等......例如,一个网络邮件应用程序可能打开并在同一个实际浏览器上文档很长一段时间进行大量的用户和服务器交互。
  3. 定期创建和销毁大量 DOM 元素的网页,就像定期使用 ajax 获取一堆新 HTML 的网页一样。

我并不真正担心泄漏的地方:

  1. 没有用户可以执行的长时间运行的交互集的网页。
  2. 在加载其他页面或重新加载此页面之前,网页不会在屏幕上停留很长时间。

我密切关注的一些关键事项。

  1. 创建/销毁 DOM 元素时包含对 DOM 元素的引用的任何持久 JS 变量或属性。
  2. 包含对其他 DOM 对象的引用的 DOM 对象的任何属性,或对包含对其他 DOM 对象的引用的 JS 对象的引用(这可能会在 JS/DOM 之间创建循环引用和交叉引用,某些较旧的浏览器无法释放这些引用)。
  3. 我加载供临时使用的任何大型数据结构。我确保不保留对这些大型数据结构的引用。
  4. 任何数据缓存。确保没有缓存任何您不想缓存的大数据。确保所有重复使用的缓存不会永远累积,并具有某种老化机制来清除旧对象。

A good javascript developer would be aware of various design patterns that can lead to memory leaks and you'd avoid coding anything that could turn in to a leak in pretty much all the pages you code.

For example, keeping a reference to any DOM object in a javascript variable will keep that DOM object alive in memory even if it's long since been removed from the DOM and you intended for it to be freed.

Practically speaking, leaks are only significant in some circumstances. Here's where I specifically worry about them:

  1. Anything I'm doing repetitively on a timer, particularly if it can be left running for a long time. For example, if you have a slideshow that might just loop forever, you have to make absolutely sure that nothing in the slideshow is an accumulating leak of either JS or DOM objects.
  2. A web page that works like an app and the user may stay on the same page for a long time, interacting with the page, doing ajax calls, etc... For example a web mail app might be open and on the same actual browser document for a very long time doing lots and lots of user and server interactions.
  3. A web page that regularly creates and destroys lots of DOM elements like something that regularly uses ajax to fetch a bunch of new HTML.

Places where I don't really worry about leaks:

  1. A web page that doesn't have a long running set of interactions the user can do.
  2. A web page that doesn't stay on screen very long before some other page is loaded or this page is reloaded.

Some of the key things I keep an eye out for.

  1. Any lasting JS variables or properties that contain references to DOM elements when DOM elements are being created/destroyed.
  2. Any properties of a DOM object that contain references to other DOM objects or references to JS objects that contain reference to other DOM objects (this can create circular references and cross references between JS/DOM that some older browsers have trouble freeing).
  3. Any large data structures that I load for temporary use. I make sure that no references to these large data structures are every kept around.
  4. Any data caches. Make sure nothing really large gets cached that you don't want cached. Make sure all caches that get used repeatedly don't accumulate forever and have some sort of aging mechanism to get rid of old objects.
放赐 2024-12-11 13:18:21

是的,内存泄漏绝对是 JavaScript 中的一个问题,因为循环引用确实是可能的。内存泄漏的一个非常常见的来源是闭包的使用。举个例子,考虑一下:

var outerFunction = function(param1, param2, param3) {
     var innerFunction = function() {};
     return innerFunction;
};

上面的代码有可能泄漏参数,因为 innerFunction 保存了对其构造范围的引用,其中包括该框架的参数。

虽然在许多有大量 RAM 的台式计算机上,这些事情很容易被忽视,但实际上,在 RAM 有限的设备(例如移动电话或机顶盒)上,这一点可能非常明显。举个有趣的例子,当我从 RAM 非常有限的电视上访问一些未命名的网站时,我经常崩溃。

请注意,这些问题与 Web 开发人员编写的 JavaScript 代码有关。底层 JavaScript 解释器中的内存泄漏虽然可能存在,但远不是一个问题,而且 Web 开发人员不必担心,因为这是浏览器编写者的工作。

Yes, memory leaks are definitely a problem in JavaScript, since circular references are indeed possible. A very common source of memory leaks is the use of closures. As an example, consider:

var outerFunction = function(param1, param2, param3) {
     var innerFunction = function() {};
     return innerFunction;
};

It is possible for the above to leak the parameters, since innerFunction holds a reference to the scope in which it was constructed, which includes the parameters to that frame.

While it is easy for these sorts of things to go unnoticed on many desktop computers, where there is plenty of RAM, this is actually something that can be very obvious on devices with limited RAM (e.g. a mobile phone or a set top box). As an anecdotal example, a couple websites that shall remain unnamed used to crash on me quite frequently when visited from my TV, which has very limited RAM.

Note that these problems are with the JavaScript code written by web developers. Memory leaks in the underlying JavaScript interpreters, while possible, are far less of an issue, and isn't something that web developers can reasonably concern themselves about, since that's the job of the browser writers.

乜一 2024-12-11 13:18:21

不。

更完整的答案:也许吧。您问得如此含糊,这是一个强烈的信号,表明您个人不太可能需要担心。

实际上,绝大多数 JavaScript 代码根本不担心它,也不需要担心它,因为只有在特定情况下,页面中的内存泄漏才会最终影响用户。浏览器和框架很好地覆盖了你的屁股。

您只需回答几个问题:

问:您是否支持大量使用 JavaScript 的丰富单页应用程序?

如果没有,那就不要浪费时间担心。如果您(或您的质量检查或您的客户)发现页面存在内存过度使用问题,请在出现问题时修复它。

问:你们需要支持移动设备吗?并且你们大量使用 javascript 吗?

移动设备的内存有限,需要格外小心。

如果您正在开发一个 JavaScript 密集型应用程序,并且需要担心内存使用情况,那么...

对对象的“脏”引用问题会导致 JavaScript 对象和 DOM 对象永远不会被垃圾收集对于某些类型的 JavaScript 应用程序很重要。永久增长的缓存、意外的全局引用以及闭包内意外的引用都可能是一个问题。

Chrome 的 Web Inspector 中的堆快照工具可以提供帮助。

这是一个 git 项目,它有一个有用的 writup 并可以遍历 javascript 对象: https://github.com/ tlrobinson/leakhelper

还有其他工具可以帮助您,但随着时间的推移,我编写了自己的工具:
1.我们的框架标记了已删除的小部件,因此我编写了代码来从窗口或文档中遍历所有数组和对象,查找到已删除对象的路径(JavaScript 代码无法遍历闭包,但它确实有助于发现一些泄漏)。
2.我使用的另一个技巧是当小部件 x 被删除时,我执行 x.leakhelper = window.createElement('leakhelper') 并 setAttribute 小部件的 oid,但不将元素添加到文档中。如果 DOM 元素没有被垃圾回收,那么小部件必须在某处有一个对其的悬空引用。在 IE 中使用 window.collectGarbage() 强制进行 GC,并使用 sIEve 来检测泄漏的 DOM 元素(我发现 sIEve 非常有用)。

过时的问题:您是否需要大力支持 IE6 或 IE7 并且您大量使用 JavaScript?您过去读到的大多数可怕的泄密事件仅发生在 << IE8。如果您支持 IE6 或 IE7,那么您需要好运和毅力(所有框架都会泄漏,并且即使使用完美的框架也很难编写不兼容的代码 - 我最终编写了自己的 IE 防泄漏代码供我们的生产使用适用于 IE6/7 用户)。即使您关闭页面,IE6/IE7 的泄漏也会持续 - 这就是它们如此令人讨厌的原因。

NO.

More complete answer: maybe. The fact you are asking so vaguely is a strong signal that you personally are unlikely to need to worry.

In practice, the vast majority of JavaScript code simply doesn't worry about it, and doesn't need to worry about it because only in particular circumstances do memory leaks in pages end up affecting users. The browser and frameworks cover your arse pretty well.

There are only a few questions you need to answer:

Q: Are you supporting a rich single page application that uses JavaScript heavily?

If not, then don't waste your time worrying. If you (or your QA, or your clients) find a memory over-usage issue with a page then fix it when it comes up.

Q: Do you need to support mobile devices, and you have heavy javascript usage?

Mobile devices have limited memory and extra care needs to be taken.

If you ARE developing a JavaScript heavy application, and you need to worry about memory usage, then...

The issue of "dirty" references to objects that cause JavaScript objects and DOM objects to never get garbage collected is important to certain types of JavaScript applications. Caches that grow forever, unexpected global references, and unexpected references inside closures can be a problem.

The Heap Snapshot tool in Chrome's Web Inspector can help.

Here is a git project that has a useful writup and walks the javascript objects it can: https://github.com/tlrobinson/leakhelper

There are other tools that help you, but I wrote my own over time:
1. our framework marks deleted widgets, so I wrote code to walk all arrays and objects from window or document looking for the paths to delected objects (javascript code can't walk closures but it definitely helped find some leaks).
2. Another trick I used was when widget x was deleted, I do a x.leakhelper = window.createElement('leakhelper') and setAttribute the oid of the widget, but not add the element into the document. If the DOM element is not garbage collected then the widget must have a dangling reference to it somewhere. In IE use window.collectGarbage() to force the GC, and use sIEve to detect the leaked DOM element (I found sIEve to be really useful).

Obsolete question: Do you need to strongly support either IE6 or IE7 AND you use JavaScript heavily? Most of the scary leaks you used to read about only occur in < IE8. If you are supporting IE6 or IE7 then you need good luck and perseverence (all frameworks leak, and it is hard to write code that doesn't even with a perfect framework - I ended up writing my own IE leak prevention code for our production use for IE6/7 users). The IE6/IE7 leaks can last even after you close your page - which is why they are so nasty.

哥,最终变帅啦 2024-12-11 13:18:21

好吧,人们仍然使用旧版本的 IE。所以要小心循环引用,因为 IE 在这方面有严重的问题。我认为在这方面常见的错误是在事件处理程序内部的闭包中引用该元素的 HTML 元素。只需将引用该元素的变量设置为 null 就可以了。

Well, people still use old versions of IE. So beware of circular references, because IE has severe problems with that. I believe the common mistake in that regard is to reference an HTML element in a closure that is inside an event handler to that element. Just set the variable referring to the element to null and it'll be fine.

怪异←思 2024-12-11 13:18:21

这实际上取决于两件事 -

  1. 应用程序的平均运行时间期望。在线商店主页上的简单 jquery 灯箱或轮播可能会泄漏(并且经常这样做,因为它们的编码非常糟糕),但没有人会注意到(因为页面在几分钟或更短的时间内关闭或刷新)。但是 Node.js 服务器、全 ajax 社交网络、浏览器游戏或在线 IDE - 可以不间断地运行数小时甚至数天。

  2. 应用程序的

    I/O 复杂性。你接触 DOM、XHR/网络、文件、DOM/UI 事件的次数越多,重绘屏幕的次数就越多(无论是 canvas、html 还是 svg)——泄漏、内存占用的风险就越大(这不是泄漏)并遇到浏览器错误。

对你来说有好处的是——这两件事是相互关联的。因此,您要么像没有明天一样编写铲子代码,要么针对性能、耐用性和稳健性进行工程师。

ps:如果你非得支持IE8-,那你还不到2011年。所以你只需要担心,就像过去的美好时光

It really depends on 2 things -

  1. Average run-time expectation of your application. Simple jquery lightbox or carusel on main page of online shop can leak (and often does, because, they are coded so badly), but nobody will notice (because the page is closed or refreshed within couple of minutes or less). But Node.js server, full-ajax social network, browser game or online IDE - can run for hours or even days non-stop.

  2. I/O complexity of your application. The more you touch DOM, XHR/network, files, DOM/UI events, the more times you redraw the screen (be it canvas, html or svg) - the bigger is risk for leaks, memory hogging (which is NOT a leak) and running into browser bugs.

Good thing for you is - those two things correlate with each other. So, you either write shovel-code like no tomorrow, or engineer for performance, endurance, and robustness.

p.s.: if you have to support IE8-, you are not in 2011, yet. So you just have to worry, like in good old times.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文