about:memory

about:memory 是 Firefox 中一个特殊的页面,允许您查看、保存、加载和比较 Firefox 内存使用情况的详细测量数据。它还允许您执行其他与内存相关的操作,例如触发 GC 和 CC,转储 GC & CC 日志,以及转储 DMD 报告。它存在于所有版本中,无需任何准备即可使用。

如何生成内存报告

假设您想测量 Firefox 的内存使用情况。也许您想自己调查它,或者也许有人要求您使用 about:memory 生成“内存报告”,以便他们可以调查您遇到的问题。请按照以下步骤操作。

  • 在感兴趣的时刻(例如,一旦 Firefox 的内存使用量变得很高),打开一个新标签页,并在地址栏中输入“about:memory”,然后按“Enter”。

  • 如果您正在使用可以发送文件的通信渠道,例如 Bugzilla 或电子邮件,请点击“测量并保存...”按钮。这将打开一个文件对话框,允许您将内存报告保存到您选择的文件中。(文件名将带有 .json.gz 后缀。)然后您可以适当地附加或上传该文件。接收者将能够在他们自己的 Firefox 实例的 about:memory 中查看此文件的内容。

  • 如果您正在使用只能发送文本的通信渠道,例如网站上的评论线程,请点击“测量...”按钮。这将导致在 about:memory 中生成树状结构的文本。此结构只是文本,因此您可以将部分或全部文本复制粘贴到任何类型的文本缓冲区中。(您无需截图。)此文本包含的测量数据少于内存报告文件,但通常足以诊断问题。不要重复点击“测量...”按钮,因为这会导致 about:memory 本身的内存使用量上升,因为它会丢弃并重新生成大量 DOM 节点。

请注意,在这两种情况下,生成的数据都包含隐私敏感信息,例如您在其他标签页中打开的网页的完整列表。如果您不想共享此信息,可以在点击“测量并保存...”或“测量...”之前选中“匿名化”复选框。这将导致隐私敏感数据被删除,但也可能使其他人更难调查内存使用情况。

从文件加载内存报告

从文件加载内存报告最简单的方法是使用“加载...”按钮。您还可以使用“加载并比较...”按钮获取两个内存报告文件之间的差异。

加载 about:memory 时,也可以通过附加 file 查询字符串自动加载单个内存报告文件,例如

about:memory?file=/home/username/reports.json.gz

这在加载从 Firefox OS 设备获取的内存报告文件时最为有用。

内存报告以 gzip 压缩的 JSON 格式保存到文件中。这些文件可以按原样加载,也可以在解压缩后加载。

解释内存报告

您在 about:memory 中看到的大多数内容都有解释性工具提示。将鼠标悬停在任何按钮上以查看其功能的描述。将鼠标悬停在任何测量值上以查看其含义的描述。

[测量基础]

大多数测量值使用字节作为单位,但有些是计数或百分比。

大多数测量值在树中呈现。例如

 585 (100.0%) -- preference-service
 └──585 (100.0%) -- referent
    ├──493 (84.27%) ── strong
    └───92 (15.73%) -- weak
        ├──92 (15.73%) ── alive
        └───0 (00.00%) ── dead

叶子节点表示实际测量值;每个内部节点的值是其所有子节点的总和。

树的使用允许测量值根据需要细分为更细的类别、子类别、子子类别等,直到任意深度。单个树中的所有测量值都不重叠。

树路径可以使用“/”作为分隔符来编写。例如,preference/referent/weak/dead 表示上面示例树中最终叶子节点的路径。

可以通过点击子树来折叠或展开子树。如果您发现任何特定的树过于复杂,可以先折叠根节点下方的所有子树,然后逐渐展开感兴趣的子树。

[部分]

内存报告按进程显示,每个部分一个进程。在每个进程的测量数据中,有以下子部分。

显式分配

此部分包含一棵名为“explicit”的树,它测量通过显式调用堆分配函数(例如 mallocnew)以及非堆分配函数(例如 mmapVirtualAlloc)分配的所有内存。

以下是一个浏览器会话的示例,其中打开了 cnn.com、techcrunch.com 和 arstechnica.com 的标签页。为了便于演示,已展开了一些子树,并折叠了其他子树。

191.89 MB (100.0%) -- explicit
├───63.15 MB (32.91%) -- window-objects
│   ├──24.57 MB (12.80%) -- top(http://edition.cnn.com/, id=8)
│   │  ├──20.18 MB (10.52%) -- active
│   │  │  ├──10.57 MB (05.51%) -- window(http://edition.cnn.com/)
│   │  │  │  ├───4.55 MB (02.37%) ++ js-compartment(http://edition.cnn.com/)
│   │  │  │  ├───2.60 MB (01.36%) ++ layout
│   │  │  │  ├───1.94 MB (01.01%) ── style-sheets
│   │  │  │  └───1.48 MB (00.77%) -- (2 tiny)
│   │  │  │      ├──1.43 MB (00.75%) ++ dom
│   │  │  │      └──0.05 MB (00.02%) ── property-tables
│   │  │  └───9.61 MB (05.01%) ++ (18 tiny)
│   │  └───4.39 MB (02.29%) -- js-zone(0x7f69425b5800)
│   ├──15.75 MB (08.21%) ++ top(http://techcrunch.com/, id=20)
│   ├──12.85 MB (06.69%) ++ top(http://arstechnica.com/, id=14)
│   ├───6.40 MB (03.33%) ++ top(chrome://browser/content/browser.xul, id=3)
│   └───3.59 MB (01.87%) ++ (4 tiny)
├───45.74 MB (23.84%) ++ js-non-window
├───33.73 MB (17.58%) ── heap-unclassified
├───22.51 MB (11.73%) ++ heap-overhead
├────6.62 MB (03.45%) ++ images
├────5.82 MB (03.03%) ++ workers/workers(chrome)
├────5.36 MB (02.80%) ++ (16 tiny)
├────4.07 MB (02.12%) ++ storage
├────2.74 MB (01.43%) ++ startup-cache
└────2.16 MB (01.12%) ++ xpconnect

需要一定的专业知识才能完全理解这里的所有细节,但有一些值得注意的事情。

  • 树根处的“explicit”值表示通过显式调用分配函数分配的所有内存。

  • “window-objects”子树表示所有 JavaScript window 对象,其中包括浏览器标签页和 UI 窗口。例如,“top(http://edition.cnn.com/, id=8)”子树表示打开到 cnn.com 的标签页,“top(chrome://browser/content/browser.xul, id=3)”表示主浏览器 UI 窗口。

  • 每个窗口的测量数据中都有 JavaScript (“js-compartment(…)” 和 “js-zone(…)”)、布局、样式表、DOM 和其他内容的子树。

  • 很明显,cnn.com 标签页使用的内存比 techcrunch.com 标签页多,而 techcrunch.com 标签页使用的内存比 arstechnica.com 标签页多。

  • 名称类似于“(2 tiny)”的子树是插入的人工节点,用于允许默认情况下折叠不重要的子树。如果您在测量之前选择了“详细”复选框,则所有树都将完全展开显示,并且不会插入人工节点。

  • “js-non-window”子树表示不来自窗口,而是来自浏览器内核的 JavaScript 内存使用情况。

  • “heap-unclassified”值表示任何内存报告程序未测量的堆分配内存。这通常占“explicit”的 10-20%。如果它变得更高,则表示应添加其他内存报告程序。DMD 可用于确定应在何处添加这些内存报告程序。

  • 还有其他内容(如图像和工作线程)以及浏览器子系统(如启动缓存和 XPConnect)的测量数据。

某些附加组件的内存使用情况已识别,如下例所示。

├───40,214,384 B (04.17%) -- add-ons
│   ├──21,184,320 B (02.20%) ++ {d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}/js-non-window/zones/zone(0x100496800)/compartment([System Principal], jar:file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7Bd10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d%7D.xpi!/bootstrap.js (from: resource://gre/modules/addons/XPIProvider.jsm:4307))
│   ├──11,583,312 B (01.20%) ++ jid1-xUfzOsOFlzSOXg@jetpack/js-non-window/zones/zone(0x100496800)
│   ├───5,574,608 B (00.58%) -- {59c81df5-4b7a-477b-912d-4e0fdf64e5f2}
│   │   ├──5,529,280 B (00.57%) -- window-objects
│   │   │  ├──4,175,584 B (00.43%) ++ top(chrome://chatzilla/content/chatzilla.xul, id=4293)
│   │   │  └──1,353,696 B (00.14%) ++ top(chrome://chatzilla/content/output-window.html, id=4298)
│   │   └─────45,328 B (00.00%) ++ js-non-window/zones/zone(0x100496800)/compartment([System Principal], file:///Users/njn/Library/Application%20Support/Firefox/Profiles/puna0zr8.new/extensions/%7B59c81df5-4b7a-477b-912d-4e0fdf64e5f2%7D/components/chatzilla-service.js)
│   └───1,872,144 B (00.19%) ++ [email protected]/js-non-window/zones/zone(0x100496800)

还有更多值得注意的事情。

  • 某些附加组件通过名称识别,例如 Tree Style Tab。其他附加组件仅通过十六进制标识符识别。您可以在 about:support 中查看特定标识符属于哪个附加组件。例如,59c81df5-4b7a-477b-912d-4e0fdf64e5f2 是 Chatzilla。

  • 附加组件的所有 JavaScript 内存使用情况都单独测量,并在该子树中显示。

  • 对于使用单独窗口的附加组件(例如 Chatzilla),这些窗口的内存使用情况将显示在此子树中。

  • 对于使用 XUL 覆盖的附加组件(例如 AdBlock Plus),这些覆盖的内存使用情况不会显示在此子树中;它将位于非附加组件子树中,并且无法识别为由附加组件引起。

其他测量

此部分包含多个树,包括许多跨越“explicit”树中测量数据的树。例如,在“explicit”树中,所有 DOM 和布局测量数据都按窗口细分,但在“其他测量”中,这些测量数据聚合为整个浏览器的总数,如下例所示。

26.77 MB (100.0%) -- window-objects
├──14.59 MB (54.52%) -- layout
│  ├───6.22 MB (23.24%) ── style-sets
│  ├───4.00 MB (14.95%) ── pres-shell
│  ├───1.79 MB (06.68%) ── frames
│  ├───0.89 MB (03.33%) ── style-contexts
│  ├───0.62 MB (02.33%) ── rule-nodes
│  ├───0.56 MB (02.10%) ── pres-contexts
│  ├───0.47 MB (01.75%) ── line-boxes
│  └───0.04 MB (00.14%) ── text-runs
├───6.53 MB (24.39%) ── style-sheets
├───5.59 MB (20.89%) -- dom
│   ├──3.39 MB (12.66%) ── element-nodes
│   ├──1.56 MB (05.84%) ── text-nodes
│   ├──0.54 MB (02.03%) ── other
│   └──0.10 MB (00.36%) ++ (4 tiny)
└───0.06 MB (00.21%) ── property-tables

此部分中的一些树测量不跨越“explicit”树中测量数据的内容,例如上面“preference-service”示例中的那些。

最后,在此部分的末尾是单个测量值,如下例所示。

    0.00 MB ── canvas-2d-pixels
    5.38 MB ── gfx-surface-xlib
    0.00 MB ── gfx-textures
    0.00 MB ── gfx-tiles-waste
          0 ── ghost-windows
  109.22 MB ── heap-allocated
        164 ── heap-chunks
    1.00 MB ── heap-chunksize
  114.51 MB ── heap-committed
  164.00 MB ── heap-mapped
      4.84% ── heap-overhead-ratio
          1 ── host-object-urls
    0.00 MB ── imagelib-surface-cache
    5.27 MB ── js-main-runtime-temporary-peak
          0 ── page-faults-hard
    203,349 ── page-faults-soft
  274.99 MB ── resident
  251.47 MB ── resident-unique
1,103.64 MB ── vsize

一些值得注意的测量值如下。

  • “resident”。物理内存使用量。如果您想要一个总结内存使用量的单个测量值,这可能是最好的一个。

  • “vsize”。虚拟内存使用量。这通常比任何其他测量值(尤其是在 Mac 上)高得多。它实际上只在 32 位平台(例如 Win32)上很重要。还有“vsize-max-contiguous”(并非在所有平台上都测量,并且在本例中未显示),它指示最大的单个可用虚拟地址空间块。如果此数字很低,则很可能内存分配很快就会因缺少虚拟地址空间而失败。

  • 各种与图形相关的测量值 (“gfx-*”)。测量的指标因平台而异。图形通常是内存使用量高的来源,因此这些测量值有助于检测此类情况。