Chrome架構:僅僅打開了1個頁面,為什么有4個進程


在開始之前,我們一起看下,Chrome打開一個頁面需要啟動多少進程?你可以點擊Chrome瀏覽器右上角的“選項”菜單,選擇“更多工具”子菜單,點擊“任務管理器”,這將打開Chrome的任務管理器的窗口,如下圖

和Windows任務管理器一樣,Chrome任務管理器也是用來展示運行中Chrome使用的進程信息的。從圖中可以看到,Chrome啟動了4個進程,你也許會好奇,只是打開了1個頁面,為什么要啟動這么多進程呢?

在解答這個問題之前,我們需要了解一下進程的概念,不過由於好多人容易把進程和線程的概念混淆,從而影響后續其他概念的理解,所以這里我就將這兩個概念以及它們之間的關系一並為你講解下。

#進程和線程

不過,在介紹進程和線程之前,我需要先講解下什么是並行處理,因為如果你理解了並行處理的概念,那么再理解進程和線程之間的關系就會變得輕松許多。

#什么是並行處理

計算機中的並行處理就是同一時刻處理多個任務,比如我們要計算下面這三個表達式的值,並顯示出結果

A = 1+2
B = 20/5
C = 7*8

在編寫代碼的時候,我們可以把這個過程拆分為四個任務:

  • 任務1 是計算A=1+2;
  • 任務2 是計算B=20/5;
  • 任務3 是計算C=7*8;
  • 任務4 是顯示最后計算的結果

正常情況下程序可以使用單線程來處理,也就是分四步按照順序分別執行這四個任務。

如果采用多線程,會怎么樣呢?我們只需分“兩步走”:第一步,使用三個線程同時執行前三個任務;第二步,再執行第四個顯示任務。

通過對比分析,你會發現用單線程執行需要四步,而使用多線程只需要兩步。因此,使用並行處理能大大提升性能

#線程 VS 進程

多線程可以並行處理任務,但是線程是不能單獨存在的,它是由進程來啟動和管理的。那什么又是進程呢?

一個進程就是一個程序的運行實例。詳細解釋就是,啟動一個程序的時候,操作系統會為該程序創建一塊內存,用來存放代碼、運行中的數據和一個執行任務的主線程,我們把這樣的一個運行環境叫進程。

為了讓你更好地理解上述計算過程,我畫了下面這張對比圖

從圖中可以看到,線程是依附於進程的,而進程中使用多線程並行處理能提升運算效率。

總結來說,進程和線程之間的關系有以下4個特點

1. 進程中的任意一線程執行出錯,都會導致整個進程的崩潰。

我們可以模擬以下場景:

A = 1+2
B = 20/0
C = 7*8

我把上述三個表達式稍作修改,在計算B的值的時候,我把表達式的分母改成0,當線程執行到B = 20/0時,由於分母為0,線程會執行出錯,這樣就會導致整個進程的崩潰,當然另外兩個線程執行的結果也沒有了

2. 線程之間共享進程中的數據。

如下圖所示,線程之間可以對進程的公共數據進行讀寫操作。

從上圖可以看出,線程1、線程2、線程3分別把執行的結果寫入A、B、C中,然后線程2繼續從A、B、C中讀取數據,用來顯示執行結果。

3. 當一個進程關閉之后,操作系統會回收進程所占用的內存。

當一個進程退出時,操作系統會回收該進程所申請的所有資源;即使其中任意線程因為操作不當導致內存泄漏,當進程退出時,這些內存也會被正確回收。

比如之前的IE瀏覽器,支持很多插件,而這些插件很容易導致內存泄漏,這意味着只要瀏覽器開着,內存占用就有可能會越來越多,但是當關閉瀏覽器進程時,這些內存就都會被系統回收掉

4. 進程之間的內容相互隔離。

進程隔離是為保護操作系統中進程互不干擾的技術,每一個進程只能訪問自己占有的數據,也就避免出現進程A寫入數據到進程B的情況。正是因為進程之間的數據是嚴格隔離的,所以一個進程如果崩潰了,或者掛起了,是不會影響到其他進程的。如果進程之間需要進行數據的通信,這時候,就需要使用用於進程間通信(IPC)的機制了。

#單進程瀏覽器時代

在了解了進程和線程之后,我們再來一起看下單進程瀏覽器的架構。顧名思義,單進程瀏覽器是指瀏覽器的所有功能模塊都是運行在同一個進程里,這些模塊包含了網絡、插件、JavaScript運行環境、渲染引擎和頁面等。其實早在2007年之前,市面上瀏覽器都是單進程的。單進程瀏覽器的架構如下圖所示

如此多的功能模塊運行在一個進程里,是導致單進程瀏覽器不穩定、不流暢和不安全的一個主要因素。下面我就來一一分析下出現這些問題的原因

問題1:不穩定

早期瀏覽器需要借助於插件來實現諸如Web視頻、Web游戲等各種強大的功能,但是插件是最容易出問題的模塊,並且還運行在瀏覽器進程之中,所以一個插件的意外崩潰會引起整個瀏覽器的崩潰。

除了插件之外,渲染引擎模塊也是不穩定的,通常一些復雜的JavaScript代碼就有可能引起渲染引擎模塊的崩潰。和插件一樣,渲染引擎的崩潰也會導致整個瀏覽器的崩潰

問題2:不流暢

從上面的“單進程瀏覽器架構示意圖”可以看出,所有頁面的渲染模塊、JavaScript執行環境以及插件都是運行在同一個線程中的,這就意味着同一時刻只能有一個模塊可以執行。

比如,下面這個無限循環的腳本:

function freeze() { while (1) { console.log("freeze"); } } freeze(); 

如果讓這個腳本運行在一個單進程瀏覽器的頁面里,你感覺會發生什么?

因為這個腳本是無限循環的,所以當其執行時,它會獨占整個線程,這樣導致其他運行在該線程中的模塊就沒有機會被執行。因為瀏覽器中所有的頁面都運行在該線程中,所以這些頁面都沒有機會去執行任務,這樣就會導致整個瀏覽器失去響應,變卡頓。這塊內容要繼續往深的地方講就到頁面的事件循環系統了,具體相關內容我會在后面的模塊中為你深入講解。

除了上述腳本或者插件會讓單進程瀏覽器變卡頓外,頁面的內存泄漏也是單進程變慢的一個重要原因。通常瀏覽器的內核都是非常復雜的,運行一個復雜點的頁面再關閉頁面,會存在內存不能完全回收的情況,這樣導致的問題是使用時間越長,內存占用越高,瀏覽器會變得越慢

問題3:不安全

這里依然可以從插件和頁面腳本兩個方面來解釋該原因。

插件可以使用C/C++等代碼編寫,通過插件可以獲取到操作系統的任意資源,當你在頁面運行一個插件時也就意味着這個插件能完全操作你的電腦。如果是個惡意插件,那么它就可以釋放病毒、竊取你的賬號密碼,引發安全性問題。

至於頁面腳本,它可以通過瀏覽器的漏洞來獲取系統權限,這些腳本獲取系統權限之后也可以對你的電腦做一些惡意的事情,同樣也會引發安全問題。

以上這些就是當時瀏覽器的特點,不穩定,不流暢,而且不安全。這是一段不堪回首的過去,也許你沒有經歷過,不過你可以想象一下這樣的場景:當你正在用瀏覽器打開多個頁面時,突然某個頁面崩潰了或者失去響應,隨之而來的是整個瀏覽器的崩潰或者無響應,然后你發現你給老板寫的郵件頁面也隨之消失了,這時你的心情會不會和頁面一樣崩潰呢

#多進程瀏覽器時代

好在現代瀏覽器已經解決了這些問題,是如何解決的呢?這就得聊聊我們這個“多進程瀏覽器時代”了

#早期多進程架構

你可以先看看下面這張圖,這是2008年Chrome發布時的進程架構。

從圖中可以看出,Chrome的頁面是運行在單獨的渲染進程中的,同時頁面里的插件也是運行在單獨的插件進程之中,而進程之間是通過IPC機制進行通信(如圖中虛線部分)。

我們先看看如何解決不穩定的問題。由於進程是相互隔離的,所以當一個頁面或者插件崩潰時,影響到的僅僅是當前的頁面進程或者插件進程,並不會影響到瀏覽器和其他頁面,這就完美地解決了頁面或者插件的崩潰會導致整個瀏覽器崩潰,也就是不穩定的問題。

接下來再來看看不流暢的問題是如何解決的。同樣,JavaScript也是運行在渲染進程中的,所以即使JavaScript阻塞了渲染進程,影響到的也只是當前的渲染頁面,而並不會影響瀏覽器和其他頁面,因為其他頁面的腳本是運行在它們自己的渲染進程中的。所以當我們再在Chrome中運行上面那個死循環的腳本時,沒有響應的僅僅是當前的頁面。

對於內存泄漏的解決方法那就更簡單了,因為當關閉一個頁面時,整個渲染進程也會被關閉,之后該進程所占用的內存都會被系統回收,這樣就輕松解決了瀏覽器頁面的內存泄漏問題。

最后我們再來看看上面的兩個安全問題是怎么解決的。采用多進程架構的額外好處是可以使用安全沙箱,你可以把沙箱看成是操作系統給進程上了一把鎖,沙箱里面的程序可以運行,但是不能在你的硬盤上寫入任何數據,也不能在敏感位置讀取任何數據,例如你的文檔和桌面。Chrome把插件進程和渲染進程鎖在沙箱里面,這樣即使在渲染進程或者插件進程里面執行了惡意程序,惡意程序也無法突破沙箱去獲取系統權限。

好了,分析完早期的Chrome瀏覽器后,相信你已經了解了瀏覽器采用多進程架構的必要性

#目前多進程架構

不過Chrome的發展是滾滾向前的,相較之前,目前的架構又有了很多新的變化。我們先看看最新的Chrome進程架構,你可以參考下圖

從圖中可以看出,最新的Chrome瀏覽器包括:1個瀏覽器(Browser)主進程、1個 GPU 進程、1個網絡(NetWork)進程、多個渲染進程和多個插件進程

下面我們來逐個分析下這幾個進程的功能。

  • 瀏覽器進程。主要負責界面顯示、用戶交互、子進程管理,同時提供存儲等功能。
  • 渲染進程。核心任務是將 HTML、CSS 和 JavaScript 轉換為用戶可以與之交互的網頁,排版引擎Blink和JavaScript引擎V8都是運行在該進程中,默認情況下,Chrome會為每個Tab標簽創建一個渲染進程。出於安全考慮,渲染進程都是運行在沙箱模式下。
  • GPU進程。其實,Chrome剛開始發布的時候是沒有GPU進程的。而GPU的使用初衷是為了實現3D CSS的效果,只是隨后網頁、Chrome的UI界面都選擇采用GPU來繪制,這使得GPU成為瀏覽器普遍的需求。最后,Chrome在其多進程架構上也引入了GPU進程。
  • 網絡進程。主要負責頁面的網絡資源加載,之前是作為一個模塊運行在瀏覽器進程里面的,直至最近才獨立出來,成為一個單獨的進程。
  • 插件進程。主要是負責插件的運行,因插件易崩潰,所以需要通過插件進程來隔離,以保證插件進程崩潰不會對瀏覽器和頁面造成影響

講到這里,現在你應該就可以回答文章開頭提到的問題了:僅僅打開了1個頁面,為什么有4個進程?因為打開1個頁面至少需要1個網絡進程、1個瀏覽器進程、1個GPU進程以及1個渲染進程,共4個;如果打開的頁面有運行插件的話,還需要再加上1個插件進程。

不過凡事都有兩面性,雖然多進程模型提升了瀏覽器的穩定性、流暢性和安全性,但同樣不可避免地帶來了一些問題

  • 更高的資源占用。因為每個進程都會包含公共基礎結構的副本(如JavaScript運行環境),這就意味着瀏覽器會消耗更多的內存資源。
  • 更復雜的體系架構。瀏覽器各模塊之間耦合性高、擴展性差等問題,會導致現在的架構已經很難適應新的需求了

對於上面這兩個問題,Chrome團隊一直在尋求一種彈性方案,既可以解決資源占用高的問題,也可以解決復雜的體系架構的問題

#未來面向服務的架構

為了解決這些問題,在2016年,Chrome官方團隊使用“面向服務的架構”(Services Oriented Architecture,簡稱SOA)的思想設計了新的Chrome架構。也就是說 Chrome 整體架構會朝向現代操作系統所采用的“面向服務的架構” 方向發展,原來的各種模塊會被重構成獨立的服務(Service),每個服務(Service)都可以在獨立的進程中運行,訪問服務(Service)必須使用定義好的接口,通過IPC來通信,從而構建一個更內聚、松耦合、易於維護和擴展的系統,更好實現 Chrome 簡單、穩定、高速、安全的目標。如果你對面向服務的架構感興趣,你可以去網上搜索下資料,這里就不過多介紹了。

Chrome最終要把UI、數據庫、文件、設備、網絡等模塊重構為基礎服務,類似操作系統底層服務,下面是Chrome“面向服務的架構”的進程模型圖

目前Chrome正處在老的架構向服務化架構過渡階段,這將是一個漫長的迭代過程。

Chrome正在逐步構建Chrome基礎服務(Chrome Foundation Service),如果你認為Chrome是“便攜式操作系統”,那么Chrome基礎服務便可以被視為該操作系統的“基礎”系統服務層。

同時Chrome還提供靈活的彈性架構,在強大性能設備上會以多進程的方式運行基礎服務,但是如果在資源受限的設備上(如下圖),Chrome會將很多服務整合到一個進程中,從而節省內存占用。

#總結

好了,今天就到這里,下面我來簡要梳理並總結今天的內容。

本文我主要是從Chrome進程架構的視角,分析了瀏覽器的進化史。

最初的瀏覽器都是單進程的,它們不穩定、不流暢且不安全,之后出現了Chrome,創造性地引入了多進程架構,並解決了這些遺留問題。隨后Chrome試圖應用到更多業務場景,如移動設備、VR、視頻等,為了支持這些場景,Chrome的架構體系變得越來越復雜,這種架構的復雜性倒逼Chrome開發團隊必須進行架構的重構,最終Chrome團隊選擇了面向服務架構(SOA)形式,這也是Chrome團隊現階段的一個主要任務。

鑒於目前架構的復雜性,要完整過渡到面向服務架構,估計還需要好幾年時間才能完成。不過Chrome開發是一個漸進的過程,新的特性會一點點加入進來,這也意味着我們隨時能看到Chrome新的變化。

總體說來,Chrome是以一個非常快速的速度在進化,越來越多的業務和應用都逐漸轉至瀏覽器來開發,身為開發人員,我們不能坐視不管,而應該緊跟其步伐,收獲這波技術紅利


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM