JavaScript:2011 年我应该担心内存泄漏吗?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
优秀的 JavaScript 开发人员会意识到可能导致内存泄漏的各种设计模式,并且您会避免在几乎所有编码的页面中编写可能导致泄漏的任何内容。
例如,在 javascript 变量中保留对任何 DOM 对象的引用将使该 DOM 对象在内存中保持活动状态,即使它早已从 DOM 中删除并且您打算释放它。
实际上,泄漏仅在某些情况下才显着。这是我特别担心的地方:
我并不真正担心泄漏的地方:
我密切关注的一些关键事项。
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:
Places where I don't really worry about leaks:
Some of the key things I keep an eye out for.
是的,内存泄漏绝对是 JavaScript 中的一个问题,因为循环引用确实是可能的。内存泄漏的一个非常常见的来源是闭包的使用。举个例子,考虑一下:
上面的代码有可能泄漏参数,因为
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:
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.
不。
更完整的答案:也许吧。您问得如此含糊,这是一个强烈的信号,表明您个人不太可能需要担心。
实际上,绝大多数 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.
好吧,人们仍然使用旧版本的 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.这实际上取决于两件事 -
应用程序的平均运行时间期望。在线商店主页上的简单 jquery 灯箱或轮播可能会泄漏(并且经常这样做,因为它们的编码非常糟糕),但没有人会注意到(因为页面在几分钟或更短的时间内关闭或刷新)。但是 Node.js 服务器、全 ajax 社交网络、浏览器游戏或在线 IDE - 可以不间断地运行数小时甚至数天。
I/O 复杂性。你接触 DOM、XHR/网络、文件、DOM/UI 事件的次数越多,重绘屏幕的次数就越多(无论是 canvas、html 还是 svg)——泄漏、内存占用的风险就越大(这不是泄漏)并遇到浏览器错误。
对你来说有好处的是——这两件事是相互关联的。因此,您要么像没有明天一样编写铲子代码,要么针对性能、耐用性和稳健性进行工程师。
ps:如果你非得支持IE8-,那你还不到2011年。所以你只需要担心,就像过去的美好时光。
It really depends on 2 things -
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.
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.