• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

electron我是窗口的内存从500M降低到132M的

武飞扬头像
runnerdancer
帮助438

前言

  • 操作系统:macOS Mojave
  • Electron 版本:8.5.1

本次实验所使用的前端代码在这里:web-cross-platform-application

electron 代码在这里:electron-app

内存分析方法

  • chrome dev tools memory.
  • process.memoryUsage
  • webFrame.getResourceUsage。electron 提供的一个 API,可以获取渲染进程缓存所使用的内存开销。同时 electron 还可以使用webFrame.clearCache清除缓存

在这次实践中,我发现使用 webFrame.getResourceUsage 是比较靠谱的,能够帮助我们获取渲染进程各个资源的缓存占用的内存开销情况,清理不再使用的缓存。

loadURL 和 loadFile

BrowserWindow可以通过loadURL或者loadFile加载窗口。一般情况下,通过new BrowserWindow创建的窗口,一个窗口对应一个render process

const mainWindow = new BrowserWindow({
  //...
});
// mainWindow.loadURL("http://localhost:3000/memory-usage");

mainWindow.loadFile("index.html"));

但是,通过 loadURL 加载的窗口,会额外多出一个占用内存很小的render process

学新通技术网

这里需要注意,在整个应用生命周期内,不管有多少个BrowswerWindow通过loadURL加载窗口,最多只会多出一个render process

学新通技术网

进程数量

通过 new BrowserWindow 创建新的窗口,每个窗口都有一个对应的render process。这些渲染进程都是独立的,没法共享内存。通过window.open打开同源窗口时,新窗口会在同一个渲染进程(即父窗口)中创建,也就是说,无论我们通过window.open打开多少个窗口,最终只有一个render process。因此通过window open打开的窗口,是可以共享内存的。所以子窗口是可以直接使用父窗口的变量等。可以参考electron文档

学新通技术网

new BrowserWindow

这里我们通过 new BrowserWindow 创建三个新的窗口,进程数量和内存开销如下:

学新通技术网

从图中看出,4 个窗口总共 4 个 render process,这 4 个 render process 所占的内存总和差不多 500MB

当我们关闭新创建的 3 个窗口,只保留最初的窗口,我们发现,最初窗口的 render process 内存几乎没啥波动

学新通技术网

window open

为了保证条件一致,在使用window open创建窗口前,我们先停止 electron 主进程,并重启。然后点击按钮创建三个新的窗口,进程数量和内存开销如下图:

学新通技术网

从图中看出,即使是打开了 4 个窗口,整个应用生命周期内只有一个 render process,而这个 render process 所占内存开销为132.9MB因此,在打开业务功能相同的窗口的情况下,window open 能节省不少内存开销

注意上图中的 images 数量是 18。这里,我们打开的窗口内容实际上都是一样的,每个窗口都是显示 6 张图片。理论上,不论打开多少个新窗口,render process 只会缓存 6 张图片,因为这 6 张图片的 url 都是一样的。但是为了区分 url 不一样的场景,我在打开窗口时,刻意加了 id,然后在图片链接后面加了个查询参数?id=id。所以这里打开 3 个窗口,就 18 个图片 url

学新通技术网

当我们关闭新创建的 3 个窗口时,只保留最初的窗口,我们发现,render process 的内存并没有释放。如下图所示:

学新通技术网

如果我们点击 清除webFrame缓存 按钮,我们会发现 render process 内存降下来了,但是相比于创建窗口前的内存,增加了大约 20MB,如下图:

学新通技术网

这 20MB 的内存波动是怎么来的?需要深入研究

小结

  • 当我们通过 new BrowserWindow 方式创建新窗口时,主进程会为每个窗口创建一个 render process,这些 render process 加起来的内存开销还是比较大的。当我们关闭这些新创建的窗口时,最初的窗口对应的 render process 所占的内存开销几乎没有波动

  • 当我们通过 window open 方式创建新窗口时,新窗口会在父窗口的渲染进程中创建,共用一个 render process,因此这些窗口是可以共享进程内存的。上面的实践证明,通过 window open 打开新的窗口,这些窗口的内存总开销比通过new BrowserWindow创建的内存总开销小很多。但是,当我们关闭其他新创建的窗口,只保留最初的父窗口,会发现父窗口的 render process 所占的内存并没有降下来。这是因为,新窗口中所有的请求,比如这里的图片请求、脚本请求,都会经过父窗口的 render process 进行缓存,这部分缓存的内存并不会随着新窗口的关闭而清除。因此,我们需要在窗口关闭时手动调用 webFrame.clearCache() 将这些缓存清除,render process 的内存也会降下来。但是,即使是调用了 webFrame.clearCache()清除缓存,render process 的内存还是比之前增加了大概 20MB,这说明还有资源没有被释放,这个还需要研究

反复打开关闭窗口,对内存的影响

在 electron 的 issue 中,找到不少描述反复打开关闭窗口,内存会持续增加或者内存泄漏的 issue,比如这个

学新通技术网

可以在 electron 的 issue 中搜索 memory leak查看相关的 issue

在我的实践中,通过 new BrowserWindow打开的窗口,即使是反复打开关闭,内存的波动比较小,可以忽略不计。

但是,通过 window open 反复打开关闭的窗口,不论打开关闭多少次,调用 webFrame.clearCache()清除缓存后,相比最开始的状态,内存依然增加了 20MB

比如,下面是 render process 最开始的状态:

学新通技术网

点击按钮,反复打开关闭弹窗,然后点击清除 webFrame 缓存按钮,内存短时间内稳定在 50MB,如下所示:

学新通技术网

大概过了几十秒,内存又恢复了之前的 30MB 左右

学新通技术网

因此,可以猜测,之前反复打开关闭弹窗,波动的 20MB,应该是还没来得及垃圾回收。

同时,结合 process.memoryusage() 中的 rssheapToalheapUsed等参数可以发现,反复打开关闭窗口,这些参数波动不大,因此是不是可以认为没有内存泄漏?

总结

综上所述,相比于new BrowserWindow创建窗口的方式,window open具有进程单一、通信简单、数据共享方便、内存开销小、代码可维护性强等优势

通过 new BrowserWindow 创建窗口,每个窗口都是独立的进程,如果多个窗口都使用了同一个资源,比如同一张图片或者同一个脚本,那这些窗口都会独立加载这些资源

但是通过 window open 创建窗口,这些窗口共享父窗口的 render 进程,资源都是缓存在父窗口的 render 进程中。如果多个窗口都使用了同一个资源,比如同一张图片,那么这些窗口只需要加载一次,其他窗口都可以从缓存中读取。这种给资源加载带来了极大的好处,同时也有弊端,就是子窗口关闭时,我们需要手动调用 webFrame.clearCache() 清除缓存

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanggchcf
系列文章
更多 icon
同类精品
更多 icon
继续加载