一、Chrome瀏覽器的任務管理器
Chrome瀏覽器任務管理器打開方式
- Chrome瀏覽器右上角選項 - 更多工具 - 任務管理器
- 快捷鍵 Shift + Esc 打開任務管理器
Chrome瀏覽器任務管理器的作用
基於Chrome瀏覽器的任務管理器,可以查看當前瀏覽器開啟了那些進程,以及每一個進程的一些基本信息,比如:
- 進程ID
- 進程所占用的系統內存空間大小
- 進程所消耗的CPU
- 進程所消耗的網絡帶寬
- 進程的優先級
- 進程中javascripe使用的內容
- ...
Chrome打開一個頁面需要開啟哪些進程?
通過上述打開瀏覽器任務管理器的方式查看打開一個頁面瀏覽器的進程,可以看到瀏覽器並不是只開啟一個渲染進程的,而是開啟了以下7個進程,其中有些進程是每一個頁面都需要的,有些進程不是必須要開啟的。
- 瀏覽器主進程
- GPU進程
- 插件進程
- 渲染進程
- Network Service 網絡進程
- Storage Service 緩存進程
- Audio Service 音頻進程
- 備用渲染程序
- ...
二、瀏覽器中的線程與進程
在了解瀏覽器的進程和線程之間關系之前,先必須了解什么是並行處理。
單線程處理 VS 多線程並行處理
計算機中的並行處理指的是在同一時刻處理多個任務。
舉例說明:比如我們要計算下面ABC的值並且最后進行顯示
let A = 1+5;
let B = 12/2;
let C = 2*3;
假設程序用單線程來進行處理,那么應該會分為4步處理:
- 先計算A的值
- 再計算B的值
- 最后計算C的值
- 然后將ABC的值分別顯示出來
假設程序用多線程來進行處理,那么只需要分為2步處理:
- 分配三個線程同時計算各自ABC的值
- 將計算得到的ABC的值分別顯示出來
結論:處理同樣的任務,多線程要比單線程效率高,也就是並行處理能大大提升性能。
進程和線程的概念
進程的概念:
進程就是一個程序的運行實例。 用人話說就是每當計算機啟動一個程序的時候,操作系統會為這個程序創建分配一塊內存,這個內存的主要作用就是存放代碼、保存程序運行時的數據、存放一個用於執行任務的主線程,我們把這樣的一個大的運行環境叫做進程。
多線程並行處理的前提條件:
雖然多線程可以並行處理任務,但是有一個很重要的前提那就是線程是不能單獨存在的,線程必須是由進程來進行啟動和管理的。
線程依附於進程,但是進程中使用多線程來並行處理任務可以提升運算效率。
進程與線程的特點和關系
-
進程中的任意一個線程出錯,都會導致整個進程的崩潰,從而導致其他線程也出錯
-
線程之間可以共享進程中的數據,可以對進程中的公共數據進行讀寫操作
-
當一個進程退出也就是銷毀的時候,操作系統會回收該進程所占用的所有資源;即使其中任意一個線程因為操作不當導致內存泄漏,當進程退出的時候,這些內存也會被正確的回收。
-
雖然線程之間可以共享用一進程中的數據,但是不同進程之間是互相嚴格隔離的,也就是每一個進程只能訪問自己內存中的數據,從而避免系統進程間的互相干擾和紊亂,當前如果進程之間需要通信的時候,是可以基於IPC機制來進行通信。
三、單進程瀏覽器的架構
早在2007年之前,所有瀏覽器都是單進程架構,這也就意味着瀏覽器的所有功能模塊都是運行在一個進程中的,這些模塊包含了網絡、插件、js運行環境、渲染引擎和標簽頁面。可想而知,這么多的模塊運行在一個進程中,會導致瀏覽器的不穩定、不流暢和不安全。
問題一:不穩定
單進程瀏覽器不穩定的根本原因在於進程與線程的特點一,那就是一個進程中的任意一個線程出現問題,都會導致整個進程的奔潰。
早期瀏覽器的為了實現諸如web視頻、web游戲等功能,都需要借助於瀏覽器的插件來實現,但是插件有個最大的問題就是不穩定容易出問題,而且瀏覽器的插件是運行在瀏覽器的進程中的,所以只要有一個插件意外出錯都會導致整個瀏覽器的崩潰。
問題二:不流暢
在單進程瀏覽器架構中,它的進程主要由頁面線程(最主要的)、網絡線程以及其他線程三部分組成,而最核心的頁面線程中則負責所有頁面的頁面渲染、頁面呈現、javascript執行環境以及插件都運行在這個頁面線程中,拋開上述的穩定先不談,單就一個頁面線程,也就意味着同一時刻以上那么多任務只要一個可以執行。
-
某個頁面執行了無限循環的腳本
比如A頁面中在執行js代碼的時候遇到了一個無限死循環的腳本,那么這就會導致其他頁面的js腳本無法執行、頁面無法渲染等所有模塊都無法運行,從而導致瀏覽器逐漸失去響應變得卡頓不流暢。 -
復雜頁面的內存泄漏
除此之外,頁面的內存泄漏也是單行程瀏覽器變慢的一個重要原因。瀏覽器在運行一個十分復雜的頁面后關閉頁面,會導致部分內存無法被完全回收,這樣隨着使用時間越長,內存占用越高,最后瀏覽器越來越卡。
問題三:不安全
-
插件因素
插件可以使用C/C++進行編寫,基於插件可以獲取到操作系統的任意資源,意味着在瀏覽器中運行一個插件就可以完全操作你的電腦,比如某些惡意插件就基於這個原理釋放病毒、竊取計算機中的賬號密碼等。 -
頁面腳本
某些頁面腳本也可以基於瀏覽器的漏洞獲取系統權限,從而進行一些惡意操作。
四、早期多進程瀏覽器的架構
早期多進程瀏覽器的架構組成
2008年Chrome發布時的多進程架構組成為:
-
瀏覽器主進程
瀏覽器主進程主要負責下載網絡資源、管理其他子進程IPC以及顯示渲染進程中生成的圖片 -
渲染進程
渲染進程主要負責解析下載的網絡資源、渲染頁面、執行javaScript腳本以及合成網絡圖片 -
插件進程
所有插件都單獨運行在插件進程中
解決了那些問題
-
穩定
由於不再是一個進程而是多個進程,基於關系3可知進程之間是互相隔離的,一個頁面或者插件出錯影響的知識當前那個頁面的渲染進程或者插件進程,並不會影響到瀏覽器主進程或者其他頁面的渲染進程,所以這就解決了頁面或者插件運行崩潰導致整個瀏覽器崩潰的情況出現。 -
流暢
一個頁面的腳本出現無限循環,也僅僅阻塞的是該頁面的渲染進程,其他頁面和瀏覽器並不會受到影響,因為每一個標簽頁都有一個自己的渲染進程。
對於內存泄漏來說,多進程瀏覽器中的一個頁面關閉意味着該頁面的渲染進程被關閉了,基於關系2,一個進程被關閉之后該進程的所有內存都會被系統正確回收,哪怕是這個進程中的線程的某些不當操作造成了內存泄漏,所以關閉復雜頁面帶來內存泄漏的問題就解決了。
- 安全
多進程瀏覽器中每一個頁面的渲染進程是運行在安全沙箱里面的,也就是等於操作系統給進程加了一把鎖,沙箱中的程序不能讀寫硬盤上的數據,也不能獲取操作系統的權限,這就避免了安全的問題。
五、后來多進程瀏覽器的架構
多進程瀏覽器的架構組成
-
1個瀏覽器主進程
子進程管理
瀏覽器操作界面展示
用戶交互
提供瀏覽器本地存儲等功能 -
多個渲染進程(取決於打開了多少個標簽頁以及這些標簽頁是否為同一站點)
核心任務是將網絡進程提交的HTML、CSS和js解析渲染為用戶可以與之交互的網頁
值得注意的是瀏覽器的排版引擎blink和js解析V8引擎都是運行在渲染進程中的
默認情況下瀏覽器會為每一個標簽頁都創建一個渲染進程
渲染進程為了安全考慮都是運行在安全沙箱中的 -
1個GPU進程(從早期瀏覽器主進程中獨立出來的)
早期是為了實現網頁的3D CSS效果而獨立出來的一個進程
后期用來繪制網頁、Chrome自身的UI界面 -
1個網絡進程(從早期瀏覽器主進程中獨立出來的)
主要負責頁面的網絡資源加載 -
1個插件進程(取決於瀏覽器運行了多少個插件)
主要負責插件的運行,獨立一個進程避免插件崩潰造成瀏覽器主進程的崩潰 -
如果頁面有iframe,那么iframe也會運行在單獨的進程中
-
如果瀏覽器安裝了拓展,那么還有占用多個拓展進程
六、面向服務的多進程瀏覽器架構
2016年,Chrome官方使用“面向服務的架構思想”重新設計了瀏覽器的架構。
原來的各個模塊被重構成一個個獨立的服務Service,每個服務都可以在獨立的進程中運行,訪問服務必須使用定義好的接口,基於IPC來進行通信,從而構建出一個更加內聚、低耦合、易於維護和拓展的系統。
解釋:原來多進程瀏覽器的架構,是每個頁面都需要若干進程完成各自頁面的工作,現在是將各個頁面通用的功能(比如音頻、視頻、網絡等)發布為瀏覽器底層的基礎服務,不同的頁面都可以基於定義好的接口來完成通信,從而可以讓多個頁面共用一些基礎的服務。
比如:
- Storage Service 緩存進程
從原來的瀏覽器主進程中分離出來的緩存服務,主要負責提供瀏覽器本地存儲等功能 - Audio Service 音頻服務
- Video Service 視頻服務
七、問題
問題1:為什么就算是現在的Chrome多進程架構瀏覽器,也會出現單頁面卡死最終導致所有頁面都崩潰的情況呢?
同一站點的頁面可以復用渲染進程
雖然瀏覽器默認情況下會為每一個頁面都分配一個獨有的渲染進程用於渲染頁面,但是如果從一個頁面打開了新頁面,而新頁面和當前頁面屬於同一站點的話,那么Chrome不會再為該頁面打開一個一個新的渲染進程,而是直接復用父頁面的渲染進程。
哪些網頁可以稱之為同一站點(same-site)?
網頁的根域名和協議相同,那么根域名下的所有子域名和不同端口號都屬於同一站點的網頁。比如:
https://game.qq.com
https://music.qq.com
https://music.qq.com:8080
上面三個URL的協議都是https,並且根域名都是qq.com,符合同一站點的規范,所以以上三個站點會復用同一個渲染進程。在這種情況下,如果一個頁面崩潰了會導致同一站點下的所有頁面都崩潰,因為他們共用同一個渲染進程。
為什么要讓同一站點的網頁共用同一個渲染進程呢?
這是因為在同一個進程中可以共享JS的執行環境,也就是A頁面可以直接在B頁面執行腳本,由於是同一家站點,所以有這個需求需要實現。
問題2:瀏覽器的UserAgent屬性如何查看
UserAgent屬性是什么?
瀏覽器的UserAgent屬性也叫作UA,UA就是瀏覽器的身份證。一般情況下,在發送HTTP請求的時候,UA會附加在請求頭的user-agent字段中一起發送給服務器,這樣子服務器就可以知道瀏覽器的基礎信息,從而根據當前請求的瀏覽器的不同返回不同的頁面內容或者資源,舉個例子,如果是移動端那么就返回移動端的樣式,如果是PC端就返回PC端的樣式。
UserAgent屬性如何查看?
瀏覽器的UserAgent屬性被保存在window.navigator.userAgent中
Chrome的UA信息為:'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'
Mozilla的UA信息為:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0"
為什么Chrome中還包含了其他瀏覽器的內核信息?
這是因為對於服務器來說會根據請求的客戶端的UA信息來返回不同的資源,但是如果有一款新的瀏覽器的UA信息是獨一無二的,那么服務器還需要針對這個特殊的UA來做適配處理,這是不現實的。所以谷歌的Chrome的UA信息中就會加上Mozilla/5.0、AppleWebKit/537.36等這些關鍵字段,代表告訴服務器我當前的這款Chrome瀏覽器也支持Mozilla和AppleWebKit引擎。在UA信息的最后才會加上Chrome自己的標識,也就是Chrome/95.0