Electron MemoryInfo 结构解析:读懂 app.getAppMetrics() 返回的进程内存指标
【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron
Electron 应用由多个进程(主进程、渲染进程、GPU、Utility 进程等)组成,定位内存问题首先要拿到每个进程的真实占用数据。MemoryInfo就是 Electron 进程监控体系中最核心的数据结构:它被app.getAppMetrics()返回的 ProcessMetric 对象以memory字段的形态暴露给 JavaScript 层,让开发者无需依赖系统工具即可量化各进程的常驻内存、历史峰值以及 Windows 上的私有内存。读完本篇,你将掌握MemoryInfo各字段的精确语义与单位、三大平台(Windows / macOS / Linux)的实现差异,并能通过源码确认这些数字的采集来源。
MemoryInfo 结构定义
MemoryInfo 官方结构文档定义如下:
workingSetSizeInteger— 当前实际驻留物理内存(pinned to physical RAM)的内存量;peakWorkingSetSizeInteger— 历史上曾经驻留物理内存的最大值;privateBytesInteger(可选,Windows 独有)— 不被其他进程共享的内存量,例如 JS 堆或 HTML 内容占用的内存。
注意:所有统计值均以 Kilobytes(KB)为单位。这是该结构最容易被忽略的约束——如果你把数值直接当作字节用于展示或告警阈值,误差会是 1024 倍。
MemoryInfo并非独立使用,它作为 ProcessMetric 的memory字段出现:
memoryMemoryInfo - The memory information for the process.
也就是说,每次调用app.getAppMetrics()拿到的ProcessMetric数组中,每一个进程条目都附带一份MemoryInfo。
获取 MemoryInfo:app.getAppMetrics() 实战
在主进程中通过app.getAppMetrics()获取全量进程指标,示例如下:
const { app } = require('electron') app.whenReady().then(() => { const metrics = app.getAppMetrics() for (const metric of metrics) { if (metric.type === 'Browser' || metric.type === 'Tab') { console.log( `pid=${metric.pid} type=${metric.type} ` + `workingSetSize=${metric.memory.workingSetSize}KB ` + `peakWorkingSetSize=${metric.memory.peakWorkingSetSize}KB` ) } } })ProcessMetric.type的取值包括Browser、Tab、Utility、GPU、Zygote等(完整列表见 ProcessMetric 文档),配合pid与creationTime可以唯一定位一个进程(pid在进程退出后可能被系统复用,因此文档建议两者结合使用)。
平台实现差异:源码级溯源
三个平台的操作系统接口能力不同,MemoryInfo各字段的可用性与数据来源因此存在明显差异。以下分析均出自仓库源码。
Windows:完整三字段
process_metric.cc 中 Windows 分支调用 Win32 APIGetProcessMemoryInfo,将PROCESS_MEMORY_COUNTERS_EX结构直接映射到三个字段:
info.WorkingSetSize→workingSetSizeinfo.PeakWorkingSetSize→peakWorkingSetSizeinfo.PrivateUsage→privateBytes
这正是文档标注privateBytes为Windows 专属的原因:Windows 的任务管理器"专用工作集"即来自PrivateUsage。
macOS:无 privateBytes
process_metric.cc 的 macOS 分支通过 Mach 接口task_info(MACH_TASK_BASIC_INFO)采集:
info->resident_size→workingSetSizeinfo->resident_size_max→peakWorkingSetSize
Mach 的mach_task_basic_info没有"私有内存"这一概念,因此 macOS 上返回的MemoryInfo只包含前两个字段,privateBytes缺失。
Linux:JS 层从 /proc 读取
Linux 下 C++ 层不提供这两个字段,改由 JavaScript 层补全。app.ts 在process.platform === 'linux'时包装原生getAppMetrics,逐个进程读取/proc/<pid>/status,用正则提取:
VmRSS(当前常驻集)→workingSetSizeVmHWM(历史最大常驻集,High Water Mark)→peakWorkingSetSize
代码片段(摘自 lib/browser/api/app.ts):
const patternVmRSS = /^VmRSS:\s*(\d+) kB$/m const patternVmHWM = /^VmHWM:\s*(\d+) kB$/m const getProcessMemoryInfo = (pid: number) => { const file = getStatus(pid) // 读取 /proc/<pid>/status return { workingSetSize: getEntry(file, patternVmRSS), peakWorkingSetSize: getEntry(file, patternVmHWM) } }从源码结构看,Linux 分支同样不产生privateBytes——/proc/<pid>/status中虽无直接对应的"私有内存"字段,Electron 也未在此处合成该值,因此该字段在 Windows 之外均应视为可能缺失的可选值,消费端代码需做防御性处理。
MemoryInfo 与 ProcessMemoryInfo 的区分
Electron 有两套容易混淆的内存 API,注意不要混用:
| 对比项 | MemoryInfo(本文主题) | ProcessMemoryInfo |
|---|---|---|
| 来源 API | app.getAppMetrics()(主进程) | process.getProcessMemoryInfo()(process 文档)、webContents.getProcessMemoryInfo() |
| 字段 | workingSetSize/peakWorkingSetSize/privateBytes | residentSet/private/shared |
| 视角 | 对任意进程(按 pid)的操作系统级指标 | 当前(或指定 renderer)进程的 resident / private / shared 拆分 |
| 单位 | Kilobytes | Kilobytes |
process.getProcessMemoryInfo()返回的ProcessMemoryInfo走的是 Chromium 的内存插桩路径,底层实现在 electron_api_web_contents.cc:通过memory_instrumentation::MemoryInstrumentation::RequestGlobalDumpForPid请求按 pid 的内存 dump。此外文档特别提示:macOS 下 Chromium 不提供residentSet,因为系统会压缩近期未访问的内存页,private才是更能代表真实用量的字段。做跨 API 对比或监控面板时,应明确每个数字出自哪条采集链路。
验证:测试用例中的断言
仓库测试 spec/api-process-spec.ts 对process.getProcessMemoryInfo()的断言可以佐证内存指标的可靠性预期:residentSet在 Linux / Windows 上大于 0,private大于 0,shared允许为 0。这提示我们在消费MemoryInfo时也应有类似的边界意识:workingSetSize正常情况下应大于 0,若读到 0 往往意味着/proc/<pid>/status读取失败(Linux 分支中getStatus捕获异常后返回空字符串,getEntry会解析为 0)。
小结
MemoryInfo的三个字段全部以KB为单位,workingSetSize是"当前物理内存占用",peakWorkingSetSize是"历史峰值",privateBytes仅 Windows 提供,可用于观察 JS 堆、页面内容等不可共享部分;- Windows 依赖
GetProcessMemoryInfo,macOS 依赖 Machtask_info,Linux 则在 JS 层解析/proc/<pid>/status的VmRSS/VmHWM,三平台字段可用性不完全一致,跨平台代码必须容忍privateBytes缺省; MemoryInfo通过ProcessMetric.memory随app.getAppMetrics()返回,是构建 Electron 应用进程级内存监控的第一手数据源;需要区分它与ProcessMemoryInfo(process.getProcessMemoryInfo())这两条不同的采集链路。
【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考