从 Firefox 93 开始,Firefox 将监控可用的系统内存,如果系统内存变得极低,以至于即将崩溃,Firefox 将通过卸载内存占用量大但未积极使用的标签来进行响应。此功能目前已在 Windows 上启用,并将随后部署到 macOS 和 Linux。当标签被卸载时,标签将保留在标签栏中,并在下次选中时自动重新加载。标签的滚动位置和表单数据将像浏览器使用“恢复上一个窗口”选项重新启动时那样恢复。
在 Windows 上,内存不足 (OOM) 情况是我们用户报告的大量浏览器和内容进程崩溃的原因。卸载标签允许 Firefox 节省内存,从而减少崩溃并避免使用浏览器的相关中断。
我们相信这可能特别有利于在资源受限的机器上使用大量标签进行大量浏览工作的人。或者也许是那些只想玩内存密集型游戏或使用运行起来有点疯狂的网站的用户。当然,还有那些标签囤积者(这里没有判断)。Firefox 现在能够更好地应对这些情况。
我们之前曾在 Windows 上尝试过标签卸载,但我们无法克服的一个问题是,在降低浏览器内存使用率和惹恼用户之间找到平衡点是一项相当困难的任务,因为标签重新加载时会有一点延迟,而且我们从未得到令人满意的结果。
我们现在通过改进我们的低内存检测和标签选择算法,并将操作范围缩小到我们确定可以为用户带来益处的案例,再次解决了这个问题:如果浏览器即将崩溃。最近,我们一直在 Nightly 频道上进行一项实验,以监控标签卸载对浏览器使用情况和用户遇到的崩溃次数的影响。我们从该实验中看到了令人鼓舞的结果。我们将继续监控结果,因为此功能将在 Firefox 93 中发布。
通过在 Nightly 频道上进行的实验,我们希望看到用户遇到的 OOM 崩溃数量减少。但是,在一个月的实验之后,我们发现浏览器崩溃和内容进程崩溃总体上大幅减少。在剩余的崩溃中,我们发现 OOM 崩溃有所增加。最令人鼓舞的是,启用标签卸载的用户能够更长时间地使用浏览器。我们还发现浏览器的平均内存使用量有所增加。
后者看起来可能非常违反直觉,但很容易解释:幸存者偏差。就像二战期间盟军轰炸机上带有弹孔的典型例子一样,过去会崩溃的内存使用量非常高的浏览器会话现在能够通过在达到临界阈值之前卸载标签而幸存下来。
OOM 崩溃增加也令人非常违反直觉,更难解释。在引入标签卸载之前,Firefox 已经通过触发内部内存压力事件来响应 Windows 内存压力,从而允许子系统减少其内存使用量。使用标签卸载,该事件将在所有可卸载标签都被卸载后触发。
这可能解释了差异。另一个假设是,我们的标签卸载有时启动得过晚,发现标签处于无法安全卸载的状态。
例如,卸载标签需要对它的 JavaScript 堆进行垃圾回收。这需要一些额外的临时存储空间,而这些空间不可用,导致标签崩溃而不是被卸载,但仍然可以保存整个浏览器免于崩溃。
我们正在努力提高我们对这个问题和相关启发式方法的理解。但是鉴于用户明显改善的结果,我们认为没有必要再延迟发布此功能。
Firefox 何时会自动卸载标签?
当系统内存极低时,Firefox 将开始自动卸载标签。卸载标签可能会影响用户的浏览会话,因此该方法旨在仅在必要时卸载标签,以避免崩溃。在 Windows 上,Firefox 会收到来自操作系统的通知(使用CreateMemoryResourceNotification 设置),指示可用的物理内存正在减少。低物理内存的阈值没有记录,但似乎约为 6%。一旦发生这种情况,Firefox 将开始定期检查提交空间(MEMORYSTATUSEX.ullAvailPageFile)。
当提交空间达到低内存阈值时,该阈值由首选项“browser.low_commit_space_threshold_mb”定义,Firefox 将卸载一个标签,或者如果没有可卸载的标签,则会触发 Firefox 内部内存压力警告,从而允许浏览器中的子系统减少其内存使用量。然后,浏览器会等待一小段时间,然后再检查提交空间,并重复此过程,直到可用的提交空间超过阈值。
我们发现对提交空间进行检查对于预测何时会出现真正的内存不足情况至关重要。只要仍然有交换空间和物理内存可用,就不会有问题。如果我们用完了物理内存,并且有交换空间,性能会因为分页而下降,但我们不会崩溃。
在 Windows 上,即使有物理内存可用,如果系统中的提交空间不足,分配也会失败,应用程序也会崩溃,因为 Windows 不会过度分配内存,在这种情况下,它可能会拒绝将虚拟内存分配给进程。换句话说,与 Linux 不同,Windows 始终需要提交空间才能分配内存。
我们是如何最终陷入这种困境的?如果某些应用程序分配了内存,但没有访问它,Windows 不会将物理内存分配给此类未访问的内存。我们观察到图形驱动程序执行此操作,导致在有大量物理内存可用时交换空间不足。
此外,我们收集的崩溃数据表明,使用高性能机器的许多用户都处于这种情况,有些人可能认为由于他们的机器上有大量内存,因此可以将 Windows 交换空间减少到最低限度。你可以看到为什么这不是一个好主意!
Firefox 如何选择首先卸载哪些标签?
理想情况下,只有不再需要的标签才会被卸载,用户最终会重新启动浏览器或关闭已卸载的标签,而不会重新加载它们。一个自然的度量标准是考虑用户上次使用标签的时间。Firefox 按最不经常使用的时间顺序卸载标签。
播放声音、使用画中画、固定标签或使用 WebRTC(用于视频和音频会议网站)的标签的权重更高,因此它们不太可能被卸载。前台的标签永远不会被卸载。我们计划进行更多实验并继续调整算法,旨在减少崩溃,同时保持性能并对用户保持谨慎。
about:unloads
为了诊断和测试目的,已添加了一个新页面 about:unloads,用于显示标签的卸载优先级顺序,并手动触发标签卸载。此功能目前处于测试阶段,并将随 Firefox 94 一起发布。

计划在 Firefox 94 中测试的 about:unloads 页面的屏幕截图。
浏览器扩展
某些浏览器扩展已经为用户提供了卸载标签的功能。我们预计这些扩展将与自动标签卸载协同工作,因为它们使用相同的底层tabs.discard() API。虽然它可能在将来发生变化,但目前自动标签卸载仅在系统内存极低时发生,这是一个低级系统指标,WebExtensions API 无法访问。(注意:扩展可以使用 WebExtensions API 中的本机消息支持 使用单独的应用程序来实现这一点。)用户仍然可以从标签卸载扩展中获益,这些扩展可以提供更多关于何时卸载标签的控制,或者使用更激进的启发式方法来节省更多内存。
请通过在ideas.mozilla.org 上留下反馈或报告错误 来告诉我们它的工作原理。如需支持,请访问support.mozilla.org。Firefox 崩溃报告和遥测遵守我们的数据隐私原则。有关更多信息,请参阅Mozilla 隐私政策。
感谢 Gian-Carlo Pascutto、Toshihito Kikuchi、Gabriele Svelto、Neil Deakin、Kris Wright 和 Chris Peterson 对这篇博文的贡献,以及他们对开发 Firefox 中的标签卸载所做的工作。
19 条评论