一、浏览器进程与线程
1、进程与线程的概念?
- 进程是CPU中最小的资源单位;线程是CPU中最小的调度单位。
- 进程在应用上是一个程序,代表了CPU运行指令,加载保存上下文所需的时间;线程是进程中更小的单位,执行一段指令所需的时间
进程是一个程序的运行实例。启动程序时,一个操作系统为一个程序创建一个虚拟内存,用来存放代码,运行中的数据和一个运行中的主线程,这个运行环境就是进程。(虚拟内存解决了用户对硬件的无限需求和有限硬件资源之间矛盾。从操作系统看,虚拟内存是交换文件;在处理器方面看,虚拟内存是虚拟地址空间)
进程与线程之间关系有4个特点:
- 进程中只要一个线程报错,进程就会报错
- 进程结束,操作系统会回收所占内存,线程也会结束,即使进程中的线程有内存泄漏,也会直接回收
- 进程之间的内容相互隔离,每个进程都是独立的,即使有一个进程报错也不会影响其他进程,所以需要进程间互相通信
- 进程中的线程互相共享进程中的数据
2、进程与线程的区别?
- 进程可以看作一个独立应用,线程不行
- 单位:进程是CPU最小的资源单位(是能拥有资源和独立运行的最小单位);线程是CPU最小的调度单位(线程是运行在进程上的一个程序运行单位,一个进程可以有多个线程)
- 通信:进程之间通信需要根据进程通信方式(见下文);线程共享进程中的数据
- 切换开销:进程切换的开销远远大于线程,线程切换不会引起进程切换,A进程中的线程切换到B进程中的线程,会引起进程切换
- 系统开销 :撤销或创建进程时,系统会回收或重新分配资源,如内存,I/O等,进程开销远大于撤销或创建线程的开销。进程之间切换会涉及到:执行进程的CPU环境、各种状态的保存、新进程状态的设置等 ;线程之间切换只会涉及到 保存和设置少量寄存器
3、chrome浏览器中进程有哪些?

总共有五种:
1. 一个浏览器进程
主要进行界面显示,用户交互,子进程管理,提供存储等功能
2. 多个渲染进程
主要是对html、css、js等转换为用户能交互的页面,排版引擎blink和js引擎V8都是运行在这个进程,默认情况下,浏览器会为每个Tab标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
3. 一个GPU进程
以前的GPU进程初衷是为了3D CSS效果,后来UI界面也直接使用GPU绘制,浏览器就引入了GPU进程
4. 一个网络线程
主要是用于网络加载,以前是浏览器进程程中的一个模块,后来独立出来称为网络进程
5. 多个插件进程
用来执行插件,因为插件容易崩溃,所以使用插件进程隔离,防止插件对浏览器和页面造成其他影响
多进程模型提升了浏览器的稳定性、流畅性和安全性,但也带来了一些问题:
- 更高的资源占用:因为每个进程都会包含公共基础结构(如 JavaScript 运行环境),这就意味着浏览器会消耗更多的内存资源。
- 更复杂的体系架构:浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了。
4、浏览器渲染进程的线程有哪些?

总共有五种:
1. GUI渲染线程
GUI渲染进程是将HTML渲染为DOM树,将CSS渲染为CSSOM树,进行页面的渲染与绘制;当发生重绘 与 回流(重排) 时会触发这一线程
GUI渲染线程与JS引擎线程是互斥的,等JS线程运行时,GUI会挂载;GUI更新会被保存到一个队列中,等JS引擎空闲时立即执行
2. JS引擎线程
JS引擎线程JS内核,是执行脚本,解析JS脚本,运行代码;JS引擎一直等待任务队列中的任务到来,然后进行处理,一个Tab页只能有一个JS引擎线程运行js程序,最后所有的任务都会汇总到JS引擎线程中执行
JS引擎线程与GUI渲染线程互斥,所以如果JS运行时间很长,会造成页面渲染阻塞
3. 事件触发线程
事件触发线程是浏览器触发的,不是js引擎,用来控制事件循环。当js引擎处理代码块时,例如setTimeout或者浏览器内核其他线程如鼠标点击,异步请求等,会将事件存放到待处理的队尾,等js引擎处理
因为js是单线程,所以这些待处理的事件都要等js引擎空闲时处理
4. 定时器触发线程
定时器触发线程单独放在一个线程中,定时计数器不是通过JS引擎处理的,因为js是单线程,如果放到js引擎中,阻塞时就会影响计数的准确性。计数器是放到定时器触发线程中,等时间到后,添加到事件队列中,等js引擎空闲时处理
W3C 在 HTML 标准中规定,定时器的定时时间不能小于 4ms,如果是小于 4ms,则默认为 4ms。
5. 异步http请求线程
XMLHttpRequest 连接后通过浏览器新开一个线程请求;检测到状态变更时,如果设有回调函数,异步线程就会产生状态变更事件,将回调函数放入到事件队列中,等js引擎空闲时处理
5、进程之间的通信方式?
1. 管道通信
管道通信是进程中最基本的通信方式。管道是操作系统在内核中开辟一段缓冲区,进程A将需要交换的数据拷贝到缓冲区,进程B就可以读取了。
管道通信特点:
- 进程之间有血缘关系
- 只能单向通信
- 管道中是同步机制
- 依赖于文件系统
- 生命周期随进程
- 面向字节流的服务
2. 消息队列通信

消息队列就是一个消息的列表。用户可以在队列中添加信息,读取信息等。消息队列提供了一个进程向另一个进程发送数据块的方法,每个数据库有一个类型,接收进程可以接受一个含有不同类型的数据结构。
缺点是:消息队列中的数据块有最大长度限制。如果频繁的发生通信行为,需要频繁的读取消息队列中的数据到内存,相当于从一个进程拷贝到另一个进程,需要花费时间。
3. 共享内存通信
共享内存通信是一个进程创建,其他多个进程可以访问的共享内存。共享内存通信是专门设置的其他通信效率低的时候使用,优点是最快的IPC(InterProcess Communication 不同进程交换数据)方式, 缺点是多个进程竞争内存的问题,所以经常与信号量通信方式一起使用。
4. 信号量通信
信号量通信相当于一个计数器,实现进程间的互斥与同步。在共享内存中,如A进程访问内存1时,信号量的值由1变为0,等B进程访问共享内存1时,就不能访问
5. 信号通信
信号通信是Unix系统最古老的通信方式之一,操作系统通过信号来通知预先设定好的事件
6. 套接字通信
上边的管道通信,消息队列通信,共享内存通信,信号量通信都是多个进程在一台主机上进行通信。那么不同主机上的进程进行通信,需要使用Socket进行通信,例如浏览器发送http请求,服务器返回对应的数据就是Socket通信。
6、在浏览器中多个标签之间如何通信?
在浏览器中,多个标签页之间无法直接通信,本质上是通过中介者模式进行通信,通过中介者转发
1. 通过webSocket进行通信
webSocket可以传递到服务器上,所以可以使用将一个标签内容传递到服务器上,等另一个标签改变的时候,通过服务器传送给标签
2. 通过shareWorker方式
shareWorker会在页面存在的生命周期中存在唯一一个线程,在多个页面中也是这唯一的一个线程。这个时候共享线程可以当作一个中介者,使用共享线程进行转发
3. 通过localStorage
可以在一个标签页对localStorage的事件进行监听,当另一个标签页修改数据时,就可以通过监听事件来获取数据,这时候localStorage就是中介者的角色
4. postMessage
能够获得对应标签页的引用时,可以使用postMessage进行转发
7、对Service Worker的理解?
Service Worker主要是创建有效的离线体验,当点击离线后,会拦截网络请求,并根据网络是否可用来采取适当的动作、更新来自服务器的资源,可以细粒度的缓存资源。
Service worker 运行在 worker 上下文:因此它无法访问 DOM,相对于驱动应用的主 JavaScript 线程,它运行在其他线程中,所以不会造成阻塞。它被设计为完全异步;因此,同步 XHR
和 Web Storage
不能在 service worker 中使用。Service worker 只能由 HTTPS
承载
8、死锁产生的原因,如何解决死锁?
死锁是多个进程因争夺资源而产生的僵局,这种僵局,没有外力作用,将无法再向前推进。
系统资源分为:
- 不可剥夺资源:只要分配了资源,只能进程完毕后再进行下一个进程,不能强制收回。如打印机,磁带机等
- 可剥夺资源:进程分配了资源,可以被其他进程剥夺或者强制收回。CPU和主存是可剥夺资源
产生死锁的原因:
-
竞争资源:
- 竞争不可剥夺资源:例如系统中只有一台打印机,正在使用,另一个进程要求打印,就会阻塞
- 竞争临时资源:临时资源包括硬件中断、信号、消息、缓冲区内的消息等,通常消息通信顺序进行不当,则会产生死锁
-
进程间推进顺序非法:
- 若P1保持了资源R1,P2保持了资源R2,系统处于不安全状态,因为这两个进程再向前推进,便可能发生死锁。例如,当P1运行到P1:Request(R2)时,将因R2已被P2占用而阻塞;当P2运行到P2:Request(R1)时,也将因R1已被P1占用而阻塞,于是发生进程死锁
产生死锁的必要条件:
- 在一段时间内某资源仅为一进程所占用
- 保持不放:当进程因请求资源而阻塞时,对已获得的资源保持不放
- 不能剥夺资源:进程在资源未使用完之前,不能剥夺,只能使用完自己释放
- 环路等待:在发生死锁时,必然存在一个进程------资源的环形链
预防死锁方法:
- 一次性分配资源:这样就不会再有请求
- 破坏保持不放:只要有一个资源得不到分配,也不给这个进程分配其他的资源
- 破坏不能剥夺资源:当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源
- 破坏环路等待:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反
9、僵尸进程和孤儿进程是什么?
1. 僵尸进程
僵尸进程是:父进程和子进程,子进程比父进程先结束,父进程没有释放子进程的占用资源,子进程的进程仍然在系统中,这种被称为僵尸进程。
2. 孤儿进程
孤儿进程是:父进程和子进程,父进程退出了,而它的一个或多个进程还在进行,这些子进程被称为孤儿进程。孤儿进程由init进程(进程1号)收养,并对他们完成状态收集工作。