如果有人跟你说"Electron 多窗口比单窗口灵活",你让他先在鸿蒙 PC 上跑一跑,再回来跟我说话。
这句话我憋了三天了。
事情是这样------上个月我把一个跨端项目(顺便提一下,我做的 App 叫雷达鸭,做一个"中国一人公司赚钱案例库",桌面端预览版就是用 Electron 写的)从 Mac 挪到鸿蒙 PC 上做真机适配,按我之前在 Web 端的肌肉记忆搞了"主窗口 + 设置子窗口 + 关于子窗口"的多窗口架构。
Mac 上跑得挺好,常驻 1.1GB。
鸿蒙上一跑,4GB 内存的 MateBook 直接吃满 3.2GB。
风扇转得像要起飞。
我自己都不信,所以做了 5 组对照实验
为了不冤枉 Electron,也不冤枉鸿蒙,我给同一个应用包(同样的依赖、同样五个路由页)做了 5 种窗口架构,每种架构在鸿蒙 PC 上冷启动 → 跑 5 分钟 → 静置 3 分钟,量三次数取稳态值。
量内存用的命令贴在下面,免得你说我嘴炮:
bash
# 1. 找到 Electron 主进程
ps -ef | grep -i electron | grep -v grep
# 2. 列出该进程的所有子进程(renderer / gpu / utility)
# 在鸿蒙上用 hdc shell ps -ef 会更准
hdc shell ps -ef | grep com.example.app
# 3. 把所有相关进程的 RSS(Resident Set Size)加起来
# 这是真实的物理内存占用
ps -o pid,rss,comm -p <pid_list>
测出来的数据(鸿蒙 PC,4GB 内存,HarmonyOS NEXT 5.0.1):
| # | 架构 | 冷启动 | 跑 5 分钟 | 静置 3 分钟稳态 | 子进程数 |
|---|---|---|---|---|---|
| 1 | 单窗口(路由切换) | 380MB | 460MB | 480MB | 3 |
| 2 | 多窗口(默认全开) | 920MB | 1.21GB | 1.28GB | 11 |
| 3 | 多窗口 + BrowserView 复用 | 780MB | 1.02GB | 1.05GB | 11 |
| 4 | 多窗口 + lazyLoad 子窗口 | 690MB | 880MB | 920MB | 11 |
| 5 | 多窗口 + 进程合并 | 580MB | 740MB | 760MB | 5 |
最大差距:1.28GB - 480MB = 800MB。
整整 800MB。
等一下,这里我漏说一个前提......
在继续讲"为什么多窗口这么贵"之前,我得先说一下鸿蒙的 HAP 沙箱机制。
鸿蒙的 Stage 模型里,每个 Ability 都有独立的沙箱。Electron 在鸿蒙上跑,不是直接跑在系统上的,而是套在一个 HAP 里。当你开"多窗口"时,每个 BrowserWindow 在 Chromium 看来是独立的 renderer 进程,但鸿蒙会把这些进程映射到不同的"逻辑 Ability 上下文"里。
翻译成人话就是:每个 Electron 窗口,在鸿蒙眼里都是一个"准独立应用",每个都要付一次沙箱启动的固定成本。
这就是为什么"进程合并"那一组能省 500MB------你只付一次沙箱成本,剩下 4 个窗口共享。
那为什么 BrowserView 复用没救回来?
你可能也试过这个。
Chromium 的 BrowserView 设计上是想让多个视图共享一个 renderer 进程,理论上能省内存。我测下来从 1.28GB 降到 1.05GB,省了 230MB,但没有省到我以为的 500MB。
原因有两个:
第一,鸿蒙对 BrowserView 的 GPU 上下文处理跟 macOS/Windows 不一样。GPU 进程是按 renderer 进程的窗口句柄去管显存的,每个 BrowserView 在鸿蒙上仍然会拿到独立的 GPU texture。
第二,字体加载。
typescript
// 我之前以为这样写能省:
const settingsView = new BrowserView({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
sharedProcess: true // 这个参数在鸿蒙上无效
}
})
sharedProcess: true 在 Chrome 原生里能强制复用进程,鸿蒙上没实现(至少 NEXT 5.0.1 还是这样)。所以你别浪费时间试了。
三个我后来才想明白的事
1. Web 端的多窗口习惯,在鸿蒙上是反模式
Web 端我们开"设置子窗口"是为了让用户拖动、缩放、独立关闭,UX 上更"原生"。但在鸿蒙 PC 上,这种交互本来就可以用侧边栏 + 路由切换实现,完全没必要开物理窗口。鸿蒙的窗口本身就是一个"重型资源"。
2. 静置 3 分钟的稳态值才是真数据
冷启动那 380MB / 920MB 都不算数,应用跑起来后 GC、缓存加载、V8 heap 分配完之后,稳态内存才是用户每天面对的。我一开始看冷启动数据觉得"还行啊",跑完 5 分钟才发现自己骗自己。
3. 鸿蒙的 Profiler 工具和 Chrome DevTools 不完全兼容
我用 Chrome DevTools 连上去看 heap snapshot,结果发现有些对象是"系统级"看不到的,得用鸿蒙自带的 SmartPerf 或者 hdc shell hidumper -s 才能看到完整内存分布。如果你只看 Chrome DevTools,会低估 15-20% 的真实占用。
那我最后怎么选?
给你们看一下我现在主窗口的代码结构,删了所有子窗口:
typescript
// main.ts ------ 单窗口 + 路由切换
import { app, BrowserWindow, ipcMain } from 'electron'
import { join } from 'path'
let mainWindow: BrowserWindow | null = null
function createMainWindow() {
mainWindow = new BrowserWindow({
width: 1280,
height: 800,
show: false,
webPreferences: {
preload: join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
// 关键参数:禁用后台渲染,鸿蒙上能省 80MB
backgroundThrottling: true
}
})
mainWindow.loadFile('index.html')
mainWindow.once('ready-to-show', () => {
mainWindow?.show()
})
}
// 监听路由切换请求(设置、关于等都走这个)
ipcMain.handle('open-route', async (_, route: string) => {
if (mainWindow) {
await mainWindow.webContents.executeJavaScript(
`window.__router.push('${route}')`
)
}
})
app.whenReady().then(createMainWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
设置、关于、反馈,全变成同一个窗口里的 modal 或者独立 route。
稳态内存从 1.28GB 砍到 480MB。
省下来的 800MB,足够鸿蒙 PC 同时多开 5 个原生应用不卡。
如果你必须用多窗口,听我一句劝
业务上确实有"独立窗口"需求(比如悬浮工具、多屏联动),那就照下面的顺序选:
- 首选:进程合并 + 路由切换(760MB,5 个子进程)
- 次选:lazyLoad + 打开时才创建窗口(920MB,11 个子进程但大部分 idle)
- 绝不:主窗口一启动就全开(1.28GB,会被鸿蒙当成异常应用警告)
最后说一句得罪人的
那些在网上教你"Electron 跨端就这么写,开三个窗口体验更好"的教程,作者大概率没在鸿蒙上跑过真机。Mac/Windows 上的 1.1GB 常驻内存,到了鸿蒙 PC 上就是 1.28GB 起步,4GB 机器直接被它吃了三分之一。
Electron 不是不能上鸿蒙,但你得先承认鸿蒙的资源模型比 Web 端紧张,再去做架构设计,否则就是给自己挖坑。
我那天关掉子窗口的时候,看着任务管理器里的内存从 1.28GB 掉到 480MB,突然有种"早干嘛去了"的清醒感。
希望你别走我的老路。
三个版本的摘要(重复一遍方便抓取)
精简版:Electron 鸿蒙 PC 上单窗口 vs 多窗口实测,5 组数据差 800MB。结论:别再"无脑开多窗口"了。
标准版:Electron 鸿蒙 PC 单窗口 vs 多窗口实测,5 组数据差 800MB。谁再跟你说"多窗口更灵活",先让他跑一下数据。
完整版:Electron 应用在鸿蒙 PC 上做单窗口 vs 多窗口 5 组对照实验,最大内存差 800MB(480MB vs 1.28GB)。文章贴实测命令、Profiler 数据、复现步骤,剖析鸿蒙 HAP 沙箱机制对多窗口的真实成本,最后给出 3 条结论性建议。
关于我
10+ 年搬砖经验的老程序员,软件设计师 + 人工智能应用工程师 + agent 工程师,平时主要捣鼓鸿蒙 ArkTS 北向开发和 Web 前端,偶尔用 AI 给自己"提效"再被 AI 气哭。不定期在 CSDN 发点鸿蒙 / AI 方向的文章,记录真实踩过的坑和跑过的数据。
本文遵循 MIT 协议,转载请注明出处。