Javascript内存和泄漏问题
Posted
技术标签:
【中文标题】Javascript内存和泄漏问题【英文标题】:Javascript memory and leak problems 【发布时间】:2012-12-19 11:22:54 【问题描述】:我的网站是一个非常标准的电子商务网站,它不是一个 JS 支持的独立应用程序或任何东西,它只是一个使用 JS 来做标准东西的网站,以及一些 jquery 插件来做一些事情。
我正在尝试在我的网站上进行一些 JS 内存评估。我通过查看 Chrome 任务管理器和堆快照来完成此操作。
最初,我的网站在第一次加载时位于任务管理器上的 35MB(即 35,000K)和 40MB 之间。如果我同时打开其他网站的多个标签,这是所有标签中最大的。 如果我刷新页面,它会跳到 55-60,再次刷新会看到它跳到 65-70MB。
在工作流程中的正常页面上,它会在 45-65 之间波动(有时会在 75 之间波动,具体取决于您正在执行的操作)。在页面之间单击并执行工作流程会看到内存跃升至 85-100,并随着您继续浏览该站点而增加。
我尝试做一些事情,比如检查:
已检测到的节点 堆快照和查看增量 amix 的 MemoryLeakChecker 检查对象的大小我需要更深入地了解循环引用或闭包问题。
堆快照并没有透露太多,大多数顶部列表是(数组),(字符串),(系统)。快照介于 4.8MB、5.1MB、5.8MB、6.8MB 之间,并且还在增加。
结果我有几个问题:
How do I understand the different metrics between snapshot memory and task manager memory
Are there any good tutorials (apart from the ones on the Google Developers site)?
How much memory is considered acceptable? Given in the task manager my site is always the highest?
Do I have a memory leak? Apart from the steps I've described above (which I haven't found anything concrete from) is there any other ways I can find leaks?
Can you suggest any tools apart from the Chrome Dev Tools (a lot of the tools mentioned on Google for Firefox are not compatible with the latest version, eg: Leak Monitor for FF)
附带说明,我的大部分功能都是低调操作,并且不超过 200 毫秒(基于 CPU 配置文件)。我应该瞄准什么好的基准? 200ms高吗?
【问题讨论】:
当您说“刷新”时,您的意思是“F5”,对吧? 【参考方案1】:您所描述的不是内存泄漏,而是 Chrome 知道的垃圾,只要 Chrome 决定是时候执行此操作,就会将其删除。为了解释这一点,让我们仔细看看您描述的场景。
让内存“泄漏”
首先让我们打开一个新的隐身窗口(只是为了确保浏览器扩展不会影响我们的结果)并导航到 google.com。 然后,让我们打开任务管理器并启用“javascript 内存”列(通过右键单击任务管理器窗口)。我们需要此列来确保我们将“泄漏”的内存实际上是由 JavaScript 分配的。我们最终会得到这样的结果: 现在,按照您的建议,我们应该重新加载页面几次,并观察标签页的内存在上升:到目前为止,一切都很好 - 一切都与您描述的完全一样。
等一下……
但是,将光标置于非活动状态半分钟,或转到另一个选项卡,您会发现我们的“Tab:google”上的内存使用量大幅下降。这是为什么?那里发生什么了?谁为我们清理了“泄露”的内存?
内存使用下降
为了调查这个问题,让我们重复我们到目前为止所做的事情,以便“Tab:google”再次使用大量内存。然后,让我们打开 Chrome 开发者工具并在“时间轴”选项卡上开始录制。之后,让我们更改一个选项卡几秒钟,当内存下降时,停止“时间轴”上的“记录”。你应该得到这个:
在我们录制的最后几秒钟出现了神秘的“GC 事件”。正好在内存被释放的同时。巧合?没有。
GC 事件
GC 代表Garbage Collector。这是一种“尝试回收垃圾或程序不再使用的对象占用的内存”的机制。所以事实证明,我们的选项卡的内存被垃圾污染了,GC 能够一直清除这些垃圾(您甚至可以使用“时间轴”选项卡底部的按钮强制垃圾收集)。那么为什么它决定不这样做呢?为什么它等待我们停止与页面交互或更改选项卡?
懒惰的垃圾收集器
简短的回答是垃圾收集必须先“冻结”所有脚本的执行,然后才能完成任何工作。此外,它可能需要大量的 CPU 时间来执行。这可能会导致延迟、断断续续的动画、无响应的控件等。这就是 Chrome 等待正确的时刻调用垃圾收集的原因。最好的时机是在用户不看的时候。
此外,请注意“GC 事件”是连续出现的,它们之间总会有几个短暂的休息。这些中断是为了让“正常”的 JavaScript 执行,从而使垃圾收集不那么明显。
活动对象
再次查看本文顶部两个屏幕截图中的“JavaScript 内存”选项卡。您会注意到此列包含两个数字。第一个是“为 JavaScript VM 保留的内存” heap”,另一个是“多少内存活(可达)对象 include" (source)。在对应用程序进行基准测试时,您应该只担心第二个值,其余的都将由 GC 处理。
泄漏示例
可能会发生真正的 JavaScript 泄漏,即。在网络聊天应用程序中。如果随着时间的推移,它将使用越来越多的“实时”内存,而始终只显示最后 10 条消息那么我们可以谈论泄漏。这样的泄漏,最终会导致标签(或浏览器)崩溃。
结论
对于在页面上运行的脚本,重新加载页面(或转到另一个位置)等同于在 ANSI C 应用程序运行时重新启动计算机。在那之后,您应该认为脚本分配的所有内存都被清除了。在实践中,重新加载页面后可能不会立即发生这种情况的唯一原因是浏览器正在等待正确的时间进行清理。而你,作为一名网络开发者,不应该担心它。
【讨论】:
【参考方案2】:如果您仍然认为您的页面正在泄漏,您可以使用来自this question 的答案来追踪泄漏的对象。
【讨论】:
以上是关于Javascript内存和泄漏问题的主要内容,如果未能解决你的问题,请参考以下文章