LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

前端内存可观测实践

zhenglin
2026年6月3日 11:8 本文热度 81

你知道自己的页面占了多少内存吗?

不是 DevTools 里的快照,不是某一次调试时瞄到的 JS Heap 数字——我说的是生产环境里,真实用户在使用时,你的页面到底吃掉了多少内存。

多数前端对这个问题没有答案。原因很简单:以前根本没有靠谱的 API 让你在线上量这件事。

现在有了。它叫 performance.measureUserAgentSpecificMemory()。名字长得令人窒息,但它解决的问题非常精准:在生产环境中,测量你的页面使用的全部内存。

一、为什么旧 API 不够用?

你可能用过 performance.memory,它返回三个数字:usedJSHeapSizetotalJSHeapSizejsHeapSizeLimit

看起来挺好?问题一大堆:

它只量 JS 堆。你的 DOM 节点、iframe 里的内容、Web Worker 占的内存,全部不算在内。

共享堆的噪声。如果多个同源页面共享一个渲染进程,你拿到的数字可能把别人的内存也算进来了。

时机不确定。它返回的是当前时刻的瞬时快照,有可能 GC 还没跑,数字虚高。

非标准 API。它用的是"堆"这种跟浏览器内部实现强绑定的概念,无法跨浏览器标准化。

这就像量体重时穿着棉袄、背着书包,还站在别人的秤上。

维度performance.memorymeasureUserAgentSpecificMemory()
测量范围仅 JS 堆JS + DOM + iframe + Worker
共享堆干扰可能混入其他页面按页面隔离归因
测量时机即时快照(可能 GC 前)GC 后测量(噪声更低)
标准化非标准,Chrome 私有W3C 提案,目标标准化
返回方式同步异步 Promise
前提条件需要 cross-origin isolation

新 API 的核心升级是两点:量得更全(覆盖整个页面的关联执行环境),量得更准(在 GC 后测量,减少噪声)。


二、一个前提:跨源隔离

这个 API 有个门槛——你的页面必须处于跨源隔离(Cross-Origin Isolation)状态。

为什么?因为内存归因需要精确知道"这块内存属于哪个来源",如果你的页面和第三方 iframe 共享进程、没有隔离,泄露细粒度的内存信息就可能变成旁路攻击(Spectre)的帮凶。

实现跨源隔离需要在服务端设置两个 HTTP 响应头:

Cross-Origin-Opener-Policy: same-origin

Cross-Origin-Embedder-Policy: require-corp


COOP: same-origin 确保你的页面和跨源弹出窗口不共享浏览上下文组。COEP: require-corp 要求页面加载的所有跨源资源必须明确授权(通过 CORS 或 CORP)。

这不是为了给你添麻烦,而是一个安全契约:你承诺不随便加载第三方资源,浏览器才放心把精确的内存数据给你。

检测当前页面是否已隔离很简单:

if (window.crossOriginIsolated) {

  // 可以使用 measureUserAgentSpecificMemory

}

三、基本用法

API 调用本身非常简洁:

if (window.crossOriginIsolated && performance.measureUserAgentSpecificMemory) {

  try {

    const result = await performance.measureUserAgentSpecificMemory();

    console.log(result);

  } catch (error) {

    if (error instanceof DOMException && error.name === 'SecurityError') {

      console.log('安全上下文不满足');

    }

  }

}

返回的数据结构长这样:

{

  bytes: 60_100_000,         // 总内存估算值

  breakdown: [

    {

      bytes: 40_000_000,

      attribution: [{ url: "https://你的页面.com/", scope: "Window" }],

      types: ["JavaScript"]

    },

    {

      bytes: 20_000_000,

      attribution: [{

        url: "https://你的页面.com/iframe",

        container: { id: "iframe-id-a", src: "/iframe" },

        scope: "Window"

      }],

      types: ["JavaScript"]

    },

    {

      bytes: 100_000,

      attribution: [],

      types: ["DOM"]

    }

  ]

}

bytes 是总量,breakdown 是明细——拆到每个执行环境(主页面、iframe、Worker),标注了 URL、作用域和内存类型。

这比 performance.memory 的三个裸数字强到不知道哪里去了。  你不只知道"页面占了多少",还知道"是主页面占的、还是哪个 iframe 占的、是 JS 内存还是 DOM 内存"。

四、生产环境里怎么用才对

单次调用的价值有限。这个 API 真正的威力在于长期趋势监控

原文推荐了一个巧妙的采样策略:泊松过程随机采样

为什么不用 setInterval 每隔 5 分钟固定测一次?因为固定间隔的采样有系统性偏差——如果内存峰值恰好出现在你两次采样的间隙,你永远捕捉不到。

泊松过程的采样间隔服从指数分布,每个时刻被采到的概率是相等的。这是统计学里消除采样偏差的经典方法:


function measurementInterval() {

  const MEAN_INTERVAL_IN_MS = 5 * 60 * 1000; // 平均 5 分钟

  return -Math.log(Math.random()) * MEAN_INTERVAL_IN_MS;

}

-Math.log(Math.random()) 生成一个指数分布的随机数,乘以平均间隔。有时 30 秒就测一次,有时 15 分钟才测一次,但长期平均下来是每 5 分钟一次。

完整的监控器:

function scheduleMeasurement() {

  if (!window.crossOriginIsolated ||

      !performance.measureUserAgentSpecificMemory) {

    return;

  }

  setTimeout(performMeasurement, measurementInterval());

}


async function performMeasurement() {

  try {

    const result = await performance.measureUserAgentSpecificMemory();

    // 上报到你的监控系统

    reportToAnalytics({

      totalBytes: result.bytes,

      breakdown: result.breakdown,

      timestamp: Date.now(),

      url: location.href

    });

  } catch (e) {

    // 静默失败,不影响用户

  }

  // 递归调度下一次

  scheduleMeasurement();

}


scheduleMeasurement();

核心价值不在于某一次的数字,而在于同一个环境下的纵向趋势。

版本 A 平均 45MB,版本 B 上线后变成 60MB——即使你不知道绝对值是否"正确",这个 15MB 的增量就足以触发警报。这跟你体检时的血压一样:140/90 具体准不准不重要,重要的是上次是 120/80,这次高了 20。

五、三个典型使用场景

1. 发布回归检测

新版本上线后,对比前后两周的内存中位数。如果显著上升,说明新代码可能引入了泄漏。

2. A/B 测试的内存成本

开启一个实验特性后,实验组的内存消耗比对照组高 30%——这个信息可以帮你决定是否上线这个功能,或者先优化内存开销。

3. 长时间使用场景

SPA 类应用最怕的就是"用久了变慢"。用泊松采样持续监控,如果内存随会话时长单调递增,大概率有泄漏。

场景怎么看数据判断标准
版本回归前后版本的内存中位数对比升高 > 10% 需要排查
A/B 测试实验组 vs 对照组的内存分布差异显著则需评估
长会话泄漏内存 vs 会话时长的相关性正相关 = 泄漏


六、别踩的坑

不能跨浏览器比较。  不同浏览器(甚至同一浏览器的不同版本)对"内存"的定义和估算方式不同。Chrome 和 Edge 返回的数字可能差 30%,这不代表一个比另一个"更省内存",只是量法不一样。

breakdown 可能是空的。  某些浏览器可能返回空的 breakdownattribution。你的代码必须处理这种情况,不要硬编码 result.breakdown[0].attribution[0].url

本地调试有延迟。  API 的 Promise 在 GC 后才 resolve,本地测试可能要等 20 秒。如果你着急,启动 Chrome 时加参数:

chrome --enable-blink-features='ForceEagerMeasureMemory'

这会跳过等待,立刻返回结果。只用于调试,生产环境不需要。

COOP/COEP 可能影响第三方资源。  开启 COEP: require-corp 后,所有跨域资源(图片、脚本、iframe)都必须带 CORS 头或 CORP 头,否则加载失败。上线前一定要在灰度环境充分测试。


七、和 Heap Snapshot 是什么关系?

一句话总结:

measureUserAgentSpecificMemory 是体检,Heap Snapshot 是手术台。

前者告诉你"体重是多少、最近是不是变重了",后者告诉你"脂肪堆在哪里、是内脏脂肪还是皮下脂肪"。

生产环境用 measureUserAgentSpecificMemory 做趋势监控,发现异常后,本地用 Heap Snapshot 定位具体的泄漏对象和引用链。两者搭配,才是完整的内存治理方案。

如果你只想带走一句话,我建议记这个:

内存优化不是一次性修 bug,而是持续可观测的趋势管理——先量得准,才治得好。


阅读原文


该文章在 2026/6/3 11:08:29 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-9  粤公网安备44030602007207号