桌面端|Electron 崩溃问题分析(LogMessage::~LogMessage() [logging.cc : 852 + 0x0])

历经2个多月,终于验证了崩溃修复是有效的,也可以说是独家了,写这篇文章来与大家分享下。

起因

我们从 0 开始建设了「桌面端」|Electron 崩溃自行上报实现「桌面端」|Electron 崩溃自行归因分析 崩溃监控之后,需要开始分析问题,解决问题。

那从崩溃占比最高的错误问题开始:

近7天崩溃 211 次,它占了 60% 以上的崩溃,所以解决了它,整年的绩效就有的说了,降低崩溃率 60% 以上[手动狗头]。

分析

官方 issues (没有解决问题)

大眼一看,日志消息崩溃,虽然说不上为什么日志还能崩溃,但这种崩溃数量级,首先我们应该去官方里寻找下 issues,看看有没有人遇到。

相关 issues: github.com/electron/el...github.com/electron/el...

确实很好搜,看起来都是LogMessage引起的崩溃问题,而且看起来官方在 20.0.1 版本已经修复了。

electron 修复PR:github.com/electron/el...github.com/electron/el...

我们当时用的 electron 版本是 20.3.12 明显是包括这个修复的,为什么还会产生崩溃呢?

仔细看了一下修复记录:

啊 ... 这?只是把错误等级降级了,就叫做修复吗【手动狗头】

真的是上古掩耳盗铃之术,说实在话,Electron 官方看起来更新很积极,但真的是很少能解决问题。

再搜也没有相关记录了,Stack Overflow 上也没有类似记录,是大家都没遇到还是根本没几个人关心 Electron 崩溃情况?这一点笔者怀疑是猜测是没什么人关心,毕竟连崩溃分析都要自己搭 ...

崩溃排查

既然找不到市面上的解决方案,那就只能自己来了,首先也是想到既然是日志消息产生的崩溃,会不会是我们的日志有问题?比如我们 console 中特殊字符,过长过大之类的问题,但我们项目中各种 console 浩如烟海,想找到是哪个或者哪几个导致出现这个崩溃,简直是不可能。

那我们继续看堆栈信息,从中发现:

看起来跟 GPU 有关系,查询了下IntentionallyCrashBrowserForUnusableGpuProcess这个方法的崩溃问题点,它是说Browser跟 GPU 进程断开导致,继续看堆栈,也发现它确实断在进程间ipc通信上。

那这确实属于 chromium 内核问题,所以 Electron 没人解决也是看似合理了。

解决方式

那我们如何解决呢?

简单粗暴点,不要产生 GPU 进程间通信,是不是能解决问题。

source.chromium.org/search?q=in...

arduino 复制代码
app.commandLine.appendSwitch('in-process-gpu');

这个指令,Google 给的官方说明:Saves some memory by moving GPU process into a browser process thread.

意思是:通过将 GPU 进程移动到浏览器进程线程中,来节省一些内存。

但毕竟这是一个全局的改动,虽然说是节省内存,但默认不开启,也是因为会降低整体的应用的使用性能。

在无法验证这个可以修复崩溃的前提下,我们需要有巧妙的方式进行实验验证。毕竟这种疑难杂症都是不可复现,甚至就没在测试机上出现过。

那我们可用的实验方式:

【X】功能开关(桌面端未建设) 【X】AB 实验(桌面端未建设) 【X】配置下发(需单独功能单独建设)

好的,并没有趁手的实验方式。(桌面端真的是任重道远啊)

那我们只能简陋一点,通过一个白名单列表,只对发生崩溃的设备进行开启操作,来观测是否该问题会下降。尽量不影响到其他用户体验。当前没有这样的设备白名单服务端设计,所以临时先放本地,验证问题是否解决。

typescript 复制代码
/**
 * !!!: 尝试修复 LogMessage 崩溃问题
 */
export const tryFixLogMessageCrash = async () => {
    const deviceId = await getDeviceId();
    if (logMessageCrashWhiteList.includes(deviceId)) {
        console.log('in-process-gpu');
        app.commandLine.appendSwitch('in-process-gpu');
    }
};

logMessageCrashWhiteList存放出现问题的设备 ID 集合。

在 app 启动后注入。

typescript 复制代码
await app.whenReady();
await tryFixLogMessageCrash();

观测

前文也说到怎么用了2个月呢?

最开始是用了 160 个问题设备 ID,本想说可以肉眼看到崩溃率下降的情况。

然并卵,160 个设备 ID,升级到带白名单版本的设备不到10个,样本太少,根本说明不了是未出现崩溃还是崩溃修复了 ...

下个迭代,我们放宽到出现该崩溃的 460 个设备上,经过1周的观测,升级了30多个设备并没有出现该崩溃,虽然样本还是极其的少,不能确定修复的正确性,继续这样放白名单也没什么意义 ...

但通过用户反馈或者有限的观测能力来看,这行代码并没有带来额外问题,所以我们去掉设备白名单限制,改为所有 Windows 设备都生效。

经过1个版本的观测,并没有再出现此类崩溃问题,说明我们的修复是有效的。

至此,这篇文章终于可以写了 ~

后续

解决了这个崩溃最大归因问题后,第二大问题是 OOM

OOM 问题不能通过崩溃来分析解决,毕竟你不能怪压死骆驼的最后一根稻草,而是要找哪些堆栈一直没释放,这个在 App 上也是难分析的,何况是在 Electron 做的桌面端,本来 Electron 就以内存占用大闻名于世【手动狗头】。

所以下一步我们是先规划实现进程监控,先排查出是哪些进程内存占用大,结合用户行为排查出发生内存膨胀的具体点,来锁定问题。

再感叹下,用 Electron 开发确实前期比较快,但遇到问题是很难解决的,依赖两个关键三方 chromium 和 node。出了问题,Electron 锅往下一甩就算解决了【手动狗头】。至于三方什么时候解决,不干它事 ...


感谢阅读,如果对你有用请点个赞 ❤️

相关推荐
今天也想MK代码6 小时前
在Swift开发中简化应用程序发布与权限管理的解决方案——SparkleEasy
前端·javascript·chrome·macos·electron·swiftui
yqcoder9 小时前
electron 中 ipcRenderer 的常用方法有哪些?
前端·javascript·electron
yqcoder10 小时前
electron 中 ipcRenderer 作用
前端·javascript·electron
伍嘉源1 天前
关于electron进程管理的一些认识
前端·javascript·electron
yqcoder1 天前
electron 设置最小窗口缩放
前端·javascript·electron
yqcoder3 天前
区分 electron 全屏和最大化
前端·javascript·electron
li.siyuan3 天前
electron + vue 打包完成后,运行提示 electrion-updater 不存在
前端·vue.js·electron
努力挣钱的小鑫4 天前
【客户端开发】electron 中无法使用 js-cookie 的问题
前端·javascript·electron
蓝胖子不是胖子4 天前
尝鲜electron --将已有vue/react项目转换为桌面应用
vue.js·react.js·electron
非晓为骁4 天前
windows 下 electron-builder ERR_ELECTRON_BUILDER_CANNOT_EXECUTE 报错处理
javascript·windows·electron