21

我的网站是一个非常标准的电子商务网站,它不是一个 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 高吗?

4

2 回答 2

38

您所描述的不是内存泄漏,而是 Chrome 知道的垃圾,只要 Chrome 决定是时候执行它,就会将其删除。为了解释这一点,让我们仔细看看您描述的场景。

让记忆“泄漏”

  • 首先让我们打开一个新的隐身窗口(只是为了确保浏览器扩展不会影响我们的结果)并导航到 google.com。
  • 然后,让我们打开任务管理器并启用“JavaScript 内存”列(通过右键单击任务管理器窗口)。我们需要此列来确保我们将“泄漏”的内存实际上是由 JavaScript 分配的。我们最终会得到这样的结果:

首次加载

  • 现在,正如你所建议的,我们应该重新加载页面几次,并观察我们标签的内存上升:

5次以上重新加载后

到目前为止,一切都很好——一切都和你描述的一样。

等一下...

但是,让您的光标处于非活动状态半分钟,或者转到另一个选项卡,您会在我们的“Tab:google”上观察到巨大的内存使用量下降。这是为什么?那里发生什么了?谁为我们清理了“泄露”的记忆?

内存使用下降

为了调查这一点,让我们重复到目前为止所做的事情,以便“Tab:google”再次使用大量内存。然后,让我们打开 Chrome 开发者工具并在“时间轴”选项卡上开始录制。之后,让我们更改一个选项卡几秒钟,当内存下降时,停止“时间轴”上的“记录”。你应该最终得到这个:

在此处输入图像描述

在我们录制的最后几秒钟,神秘的“GC 事件”出现了。正好在内存被释放的同时。巧合?没有。

GC 事件

GC 代表垃圾收集器。这是一种“尝试回收垃圾或程序不再使用的对象占用的内存”的机制。所以事实证明,我们的选项卡的内存被垃圾污染了,GC 能够一直清除这些垃圾(您甚至可以使用“时间轴”选项卡底部的按钮强制垃圾收集)。那么为什么它决定不这样做呢?为什么它等待我们停止与页面交互或更改选项卡?

懒惰的垃圾收集器

简短的回答是垃圾收集必须“冻结”所有脚本的执行,然后才能完成任何工作。此外,它可能需要大量的 CPU 时间来执行。这可能会导致延迟、断断续续的动画、无响应的控件等。这就是 Chrome 等待合适的时机调用垃圾收集的原因。最好的时机是用户不看的时候。

此外,请注意“GC 事件”是连续出现的,它们之间总是有几个短暂的休息。这些中断是为了让“正常”的 JavaScript 执行,从而使垃圾收集不那么明显。

活动对象

再次查看本文顶部两个屏幕截图中的“JavaScript 内存”选项卡。您会注意到此列包含两个数字。第一个是“为 JavaScript VM 堆保留的内存”,另一个是“有多少内存活(可达)对象包含”(来源)。在对您的应用程序进行基准测试时,您应该只担心第二个值,其余的都将由 GC 处理。

泄漏示例

可能会发生真正的 JavaScript 泄漏,即。在网络聊天应用程序中。如果随着时间的推移,它将使用越来越多的“实时”内存,而始终只显示最后 10 条消息,那么我们可以谈论泄漏。这样的泄漏,最终会导致标签(或浏览器)崩溃。

结论

对于在页面上运行的脚本,重新加载页面(或转到另一个位置)等同于在 ANSI C 应用程序运行时重新启动计算机。在那之后,您应该认为脚本分配的所有内存都被清除了。在实践中,重新加载页面后可能不会立即发生这种情况的唯一原因是浏览器正在等待正确的时间进行清理。而作为 Web 开发人员的你,不应该担心它。

于 2013-01-07T01:04:17.540 回答
1

如果您仍然认为您的页面正在泄漏,您可以使用此问题的答案来追踪泄漏的对象。

于 2013-01-11T08:56:45.177 回答