JavaScript内存和泄漏问题

21

我的网站是标准的电商网站,不是JS支持的独立应用程序,只是一个使用JS执行标准操作和一些jquery插件做一些事情的网站。

我正在尝试对我的网站进行一些JS内存评估。通过查看Chrome任务管理器和堆快照来完成这个任务。

最初,第一次加载我的网站,在任务管理器上占用35MB(即35,000K)到40MB的空间。这是任何标签页中最大的占用内存,如果我同时打开了其他网站的多个标签页。 如果我刷新页面,它会跳到55-60,再次刷新则会跳到65-70MB。

在工作流程的普通页面上,它在45-65之间波动(有时根据您所做的内容达到75)。点击页面并从一个页面到另一个页面执行工作流程会使内存跳至85-100,并随着您继续浏览网站而增加。

我尝试过一些事情,如检查:

  • 分离的节点
  • 堆快照并查看差异
  • Amix的MemoryLeakChecker检查对象的大小

我需要更深入地查找循环引用或闭包问题。

堆快照没有显示很多信息。大部分顶部列表是(array),(string),(system)。快照大小在4.8MB,5.1MB,5.8MB,6.8MB之间并且不断增加。

我有几个问题:

  • 如何理解堆快照内存和任务管理器内存之间的不同指标?
  • 除了Google Developers网站上的教程外,还有哪些好的教程?
  • 多少内存被认为是可接受的?考虑到在任务管理器中,我的网站始终是占用最高内存的?
  • 我是否有内存泄漏?除了我上面描述的步骤(我没有找到任何确定的结果),还有其他方法可以查找泄漏吗?
  • 除了Chrome Dev Tools,你能推荐其他工具吗?(许多在谷歌上针对Firefox提到的工具都不兼容最新版本,例如:Leak Monitor for FF)
  • 顺便说一句,我的大部分功能都是低调操作,不超过200ms(基于CPU分析)。我应该追求什么样的良好基准?200ms算高吗?


    当你说“刷新”时,你是指按下“F5”键,对吗? - user166390
    2个回答

    38
    您所描述的不是内存泄漏,而是Chrome知道的垃圾,只要Chrome决定了就会将其删除。为了解释这一点,让我们更仔细地看一下您所描述的情况。
    制造内存“泄漏”
    首先,让我们打开一个新的隐身窗口(只是为了确保浏览器扩展程序不会影响我们的结果),并导航到google.com。
    然后,让我们打开任务管理器,并启用“JavaScript内存”列(通过右键单击任务管理器窗口)。我们需要此列以确保我们将“泄漏”的内存实际上是由JavaScript分配的。我们最终得到类似于以下内容:

    First load

    现在,正如您建议的那样,我们应该重新加载页面几次并观察我们选项卡的内存使用情况上升:

    After 5+ reloads

    到目前为止,一切都很顺利 - 一切都与您描述的完全相同。

    等待一下...

    但是,请让您的光标闲置半分钟,或者转到另一个选项卡,您将观察到我们的“Tab:google”上的巨大内存使用量下降。为什么会这样? 发生了什么? 谁为我们清理了“泄漏”的内存?

    内存使用量下降

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

    enter image description here

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

    GC事件

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

    懒惰的垃圾回收器

    简短的答案是,在执行任何工作之前,垃圾回收必须“冻结”所有脚本的执行。此外,执行可能需要大量的CPU时间。这可能导致延迟、卡顿动画、无响应的控件等问题。这就是为什么Chrome等待正确的时刻来调用垃圾回收。而做到这一点的最佳时机就是当用户没有看着页面时。

    此外,请注意,“GC事件”是系列的,它们之间总会有短暂的间隔时间。这些间隔时间是为了让“正常”的JavaScript执行,从而使垃圾回收变得不那么明显。
    活动对象
    再次查看本文最上方的两张截图中的“JavaScript内存”选项卡。您会注意到此列包含两个数字。第一个是“为JavaScript VM堆保留的内存”,另一个是“多少内存由活动(可访问)对象组成”(source)。在对应用程序进行基准测试时,您只需要关注第二个值,其他一切都将由GC处理。
    泄漏示例
    真正的JavaScript泄漏可能会发生在Web聊天应用程序中。如果随着时间的推移,它将使用越来越多的“活”内存,同时始终仅显示最后10条消息,那么我们就可以谈论一下泄漏了。这种泄漏最终会导致选项卡(或浏览器)崩溃。
    结论

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


    1

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


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接