欢迎光临散文网 会员登陆 & 注册

浏览器进程/线程模型

2023-03-12 19:17 作者:TongMarsh  | 我要投稿

浏览器进程架构

浏览器如何由进程和线程构建? 方案可以是单进程多线程或多个进程(通过IPC传递消息)。

这两种架构只是具体实现,并无对错,本文只讨论chrome最新的架构,示意图如下。

最上面的browser process与其他进程合作,其他进程处理不同的事项。Renderer process对应每一个tab。直到最近,Chrome会为每个tab分配进程,现在它会尝试给每个站点分配进程,包括iframe。

浏览器中的进程

Browser process控制浏览器的chrome部分(这里的chrome指外壳,不是Chrome浏览器)。包括地址栏,书签,回退/前进按钮

Renderer process控制每个tab内部的展示

Plugin process控制浏览器点插件

GPU process处理其他进程的GPU任务。之所以被拆分为单独的GPU进程是因为GPU会处理多个应用的请求,绘制在同一个表面。

另外还有Extension进程,utility进程等,具体可以从浏览器的更多工具-任务管理器中查看。

多进程架构的优势

独立性,当有多个tab时,有一个tab不响应,不会导致其他tab不响应。

另外时安全和沙盒。操作系统提供了限制进程权限的方式,浏览器可以使用沙盒机制限制进程对某些功能的权限。比如Chrome浏览器限制renderer进程对文件访问的权限。

因为每个进程有自己私有的内存空间,它们通常会包含多个公共模块的多个拷贝,比如Chrome浏览器的V8。这意味着更多的内存占用,因为进程无法像线程那样共享内存。为了节约内存,Chrome设置了进程的最大数量,具体数值取决于具体的硬件,但是当达到该限制后,Chrome会将同一个站点的多个tab合并为一个进程。

节约更多内存-服务化

上面讲了renderer进程合并以节约内存的做法,同样的方法也适用于browser进程。Chrome正通过架构变化将browser应用的各个部分当做服务运行,以便于更方便的拆分和融合。

基本思路是在强劲的硬件上,将多个服务拆成不同的进程,相反,将多个服务融合为一个进程。在Android中就有所体现。

比如上面一种是将网络/UI/存储/设备等服务用一个Browser进程,另一种是每个服务一个进程。

Site isolation

站点隔离针对的是有iframe的情况,Chrome会分配一个单独的renderer进程给iframe。前面说过每个tab一个进程的模型,它允许跨站的iframe和网页在一个进程中,同源策略是web主要的安全模型,它保证不经允许无法跨站访问数据。而进程隔离是最有效的方式。这也是一项大工程,它改变了iframe和其它的交流机制,哪怕是简单的使用Ctrl+F搜索也意味着需要检索不同的进程。这也是为什么浏览器工程师将site isolation作为一个重要里程碑。

navigation进程间的合作

来看一个简单的案例:在浏览器里输入URL,浏览器从互联网获取数据,展示页面。这里聚焦在用户请求站点,浏览器准备渲染页面这个过程-也叫作navigation。

如前所述,在tab外的都有browser进程控制,browser进程里有绘制按钮和输入框的UI线程,处理网络任务的网络线程,存储线程。当在地址栏输入一个URL,输入由browser进程的UI线程处理。

Navigation

当用户在地址栏输入,UI线程需要解析决定是关键词还是网站地址,从而是导向搜索引擎还是某个网站。

当用户输入url回车后,UI线程发起网络请求获取站点内容。tab角落显示加载提示的同时,网络线程通过必要的网络协议(DNS,TLS)请求内容。如果收到的是重定向比如301,会发起另一个URL的请求。

网络线程收到响应后,通过检查内容确定数据类型(MIME Type sniffing)。如果确定是HTML文件后,将数据传递给renderer进程,如果是压缩文件或其它文件,意味着需要将数据传给下载管理器。

确定是合规的html文件后,会创建renderer进程交由它渲染。为了加速,UI线程会提前找到/创建renderer进程。

浏览器进程将数据流交给renderer进程,并且通过IPC提交navigation任务。一旦browser进程收到renderer进程的确认后,navigation就完成了,接下来就是renderer进程的加载阶段。

到此,地址栏以及security indicator会展示网站信息,tab历史会更新。

加载完成后,Renderer进程向Browser进程发送消息,通知完成。Browser进程停止tab的loading spinner。

unload

当发生导航时,Browser进程创建新进程处理导航,旧的renderer进程处理unload回调

Service worker

Service worker 在renderer进程中运行。

网络线程会检查某个站点的service worker是否存在,如果存在UI线程找一个渲染进程执行代码

渲染进程

一个tab内的所有事情都由renderer进程处理。它的主要任务是将html,css,javascript转成可交互页面。在renderer进程中,大部分工作是主线程完成,也存在一些worker线程,另外也有compositor和raster线程

加快渲染过程

解析

有了html,主线程一边请求外链资源,一边解析构建dom树。为了加速,preload scanner会并发加载资源。它查看html解析器生成的token,向brower进程网络线程发送请求

JS阻塞解析

当html解析器发现script tag时,会暂停解析dom,去执行js代码,因为js可能会更改dom结构。因此为了加速,可以使用script标签的async/defer标志,告诉浏览器异步加载js代码,避免阻塞主线程。

<link rel="preload">也可以告诉浏览器该资源是必须的,让浏览器尽快加载。

详见:https://developers.google.com/web/fundamentals/performance/resource-prioritization

样式计算

Layout

回流(reflow)这一步是计算元素的几何信息,包括坐标,大小。产物是Layout tree,类似于dom树,多了可见性信息。当display:none时,layout tree里时没有该元素的。

Paint

有了layout 树后,还需知道绘制先后次序。这一步主线程遍历layout tree创建paint records

raster和compositing

有了元素几何信息,绘制顺序,将这些信息转换成屏幕像素就是rasterizing。但是这样子存在性能问题,现代浏览器有一种方法:compositing。将页面分成多个layer,分别rasterizing,最后组合起来。

Non-fast scrollable region

有了compositor线程,当发送滚动时,绘制就可以无需主线程。但是如果有事件回调,compositor线程会将该区域标识为Non-fast scrollable region(不能快速滑动区)。当该区域发送事件时,会将信息发给主线程。

通常,我们会通过document的事件委托处理事件,这样的弊端是整个页面都是Non-fast scrollable region,降低了性能。

getCoalescedEvents可以将多个事件批量发送给主线程,有一定的性能提升。

参考

https://developer.chrome.com/blog/inside-browser-part4/


浏览器进程/线程模型的评论 (共 条)

分享到微博请遵守国家法律