浏览器常见进程和线程

文章目录

进程和线程的联系和区别

当我们启动某个程序时,操作系统会给该程序创建一块内存(当程序关闭时,该内存空间就会被回收),用来存放代码、运行中的数据和一个执行任务的主线程,这样的一个运行环境就叫进程

而线程是依附于进程的,在进程中使用多线程并行处理能提升运算效率,进程将任务分成很多细小的任务,再创建多个线程,在里面并行分别执行

进程和线程的关系特点是这样的:

  • 进程与进程之间完全隔离,互不干扰,一个进程崩溃不会影响其他进程,避免一个进程出错影响整个程序
  • 进程与进程之间需要传递某些数据的话,就需要通过进程通信管道IPC来传递
  • 一个进程中可以并发多个线程,每个线程并行执行不同的任务
  • 一个进程中的任意一个线程执行出错,会导致这个进程崩溃
  • 同一进程下的线程之间可以直接通信和共享数据
  • 当一个进程关闭之后,操作系统会回收该进程的内存空间

早期浏览器

2007年以前浏览器并不是多进程的结构,而是单进程的结构,一个进程中包含了网络、JS运行环境、渲染引擎、页面、插件等,这也导致单进程的结构引发了很多问题

  • 一是不稳定,其中一个线程卡死,可能会导致整个程序出问题,比如打开多个标签页,其中一个标签页卡死可能会导致整个浏览器无法正常运行
  • 二是不安全,浏览器一个进程里是可以共享数据的,那JS线程岂不是可以随意访问浏览器进程内的所有数据,这显然不合理
  • 三是不流畅,一个进程需要负责太多事情,会导致运行效率问题

所以为了解决这些问题,才发展出了多进程结构

我们来看一下目前最新的Chrom有进程架构

Chrome 打开一个页面有多少进程?分别是哪些

浏览器从关闭到启动,然后新开一个页面至少需要:1个浏览器进程,1个GPU进程,1个网络进程,和1个渲染进程,一共4个进程;

后续如果再打开新的标签页:浏览器进程,GPU进程,网络进程是共享的,不会重新启动,然后默认情况下会为每一个标签页配置一个渲染进程,但是也有例外,比如从A页面里面打开一个新的页面B页面,而A页面和B页面又属于同一站点的话,A和B就共用一个渲染进程,其他情况就为B创建一个新的渲染进程

所以,最新的Chrome浏览器包括:1个浏览器主进程,1个GPU进程,1个网络进程,多个渲染进程,和多个插件进程

  1. 浏览器进程: 负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作,同时提供存储功能
  2. GPU进程:负责整个浏览器界面的渲染。Chrome刚开始发布的时候是没有GPU进程的,而使用GPU的初衷是为了实现3D CSS效果,只是后面网页、Chrome的UI界面都用GPU来绘制,这使GPU成为浏览器普遍的需求,最后Chrome在多进程架构上也引入了GPU进程
  3. 网络进程:负责发起和接受网络请求,以前是作为模块运行在浏览器进程一时在面的,后面才独立出来,成为一个单独的进程
  4. 插件进程:主要是负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响
  5. 渲染进程:负责控制显示tab标签页内的所有内容,核心任务是将HTML、CSS、JS转为用户可以与之交互的网页,排版引擎Blink和JS引擎V8都是运行在该进程中,默认情况下Chrome会为每个Tab标签页创建一个渲染进程

我们平时看到的浏览器呈现出页面过程中,大部分工作都是在渲染进程中完成,所以我们来看一下渲染进程中的线程

渲染进程中的线程

  1. GUI渲染线程:负责渲染页面,解析html和CSS、构建DOM树、CSSOM树、渲染树、和绘制页面,重绘重排也是在该线程执行
  2. JS引擎线程:一个tab页中只有一个JS引擎线程(单线程),负责解析和执行JS。它GUI渲染进程不能同时执行,只能一个一个来,如果JS执行过长就会导致阻塞掉帧
  3. 计时器线程:指setInterval和setTimeout,因为JS引擎是单线程的,所以如果处于阻塞状态,那么计时器就会不准了,所以需要单独的线程来负责计时器工作
  4. 异步http请求线程: XMLHttpRequest连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待JS引擎空闲执行
  5. 事件触发线程:主要用来控制事件循环,比如JS执行遇到计时器,AJAX异步请求等,就会将对应任务添加到事件触发线程中,在对应事件符合触发条件触发时,就把事件添加到待处理队列的队尾,等JS引擎处理

说下浏览器的进程、线程模型,线程模型中的每个线程都是干嘛用的?

Chrome为例,有四种进程模型,分别是

  1. Process-per-site-instance:默认模式。访问不同站点创建新的进程,在旧页面中打开的新页面,且新页面与旧页面属于同一站点的话会共用一个进程不会创建
  2. Process-per-site:同一站点使用同一进程
  3. Process-per-tab:每一个标签页都创建新的进程
  4. Single Process:单进程模式

线程模型中的线程都是干嘛的呢?

  1. MessagePumpForIO:处理进程间通信的线程,在Chrome中,这类线程都叫做IO线程
  2. MessagePumpForUI:处理UI的线程用的
  3. MessagePumpDefault:一般的线程用到的

每一个Chrome的线程,入口函数都差不多,都是启动一个消息循环,等待并执行任务

你知道哪些进程间通信的方式?

  1. 管道通信:就是操作系统在内核中开辟一段缓冲区,进程1可以将需要交互的数据拷贝到这个缓冲区里,进程2就可以读取了
  2. 消息队列通信:消息队列就是用户可以添加和读取消息的列表,消息队列里提供了一种从一个进程向另一个进程发送数据块的方法,不过和管道通信一样每个数据块有最大长度限制
  3. 共享内存通信:就是映射一段能被其他进程访问的内存,由一个进程创建,但多个进程都可以访问,共享进程最快的是IPC方式
  4. 信号量通信:比如信号量初始值是1,进程1来访问一块内存的时候,就把信号量设为0,然后进程2也来访问的时候看到信号量为0,就知道有其他进程在访问了,就不访问了
  5. socket:其他的都是同一台主机之间的进程通信,而在不同主机的进程通信就要用到socket的通信方式了,比如发起http请求,服务器返回数据

多标签之间怎么通信?

没有办法直接通信,需要有一个类似中介者进行消息的转发和接收,比如

  1. localStorage:在一个标签页监听localStorage的变化,然后当另一个标签页修改的时候,可以通过监听获取新数据
  2. WebSocket:因为websocket可以实现实时服务器推送,所以服务器就可以来当这个中介者。标签页通过向服务器发送数据,然后服务器再向其他标签推送转发
  3. ShareWorker:会在页面的生命周期内创建一个唯一的线程,并开启多个页面也只会使用同一个线程,标签页共享一个线程
  4. postMessage:
js 复制代码
// 发送方
window.parent().pastMessage('发送的数据','http://接收的址')
// 接收方
window.addEventListener('message',(e)=>{ let data = e.data })

你知道僵尸进程和孤儿进程吗?

  • 孤儿进程:故名思义,就是没爹的孩子。父进程退出了,而它的一个或多个进程还在运行,那么这些子进程都会成为孤儿进程。这些孤儿都将被init进程收养,并负责这些孤儿的以后
  • 僵尸进程:就是子进程比父进程先结束,而父进程又没有释放子进程占用的资源,那么子进程的描述还留在系统中,这种进程就是僵尸进程
相关推荐
ServBay2 天前
告别面条代码,PSL 5.0 重构 PHP 性能与安全天花板
后端·php
JaguarJack5 天前
FrankenPHP 原生支持 Windows 了
后端·php·服务端
BingoGo5 天前
FrankenPHP 原生支持 Windows 了
后端·php
JaguarJack6 天前
PHP 的异步编程 该怎么选择
后端·php·服务端
BingoGo6 天前
PHP 的异步编程 该怎么选择
后端·php
JaguarJack6 天前
为什么 PHP 闭包要加 static?
后端·php·服务端
ServBay7 天前
垃圾堆里编码?真的不要怪 PHP 不行
后端·php
用户962377954488 天前
CTF 伪协议
php
BingoGo10 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack10 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端