【Chrome源碼閱讀系列】Chrome多進程架構

這個文檔描述了Chromium的頂層架構設計web

問題背景

構建一個沒有crash和掛起的渲染引擎基本是不可能,構建一個徹底安全的渲染引擎也基本是不可能的。瀏覽器

在某些程度上,2006年左右的web瀏覽器就像過去單用戶、多任務合做的操做系統同樣。和一些操做系統裏發生故障的應用可能搞掛整個系統同樣,一個操做不當的web頁面也會搞掛整個瀏覽器。一個頁面或者插件的bug就可能把整個瀏覽器搞崩潰以致於全部頁面都不可能用了。安全

現代操做系統要相對更健壯一些,由於他們把應用都拆分進了獨立的進程來相互分隔。一個應用的crash一般不會影響其餘應用或者操做系統,而且每一個用戶和其餘用戶的數據訪問也是有限制的。網絡

架構概述

咱們給每一個瀏覽器tab頁都使用了獨立的進程來保護大部分的應用不受渲染引擎的bug和故障影響。咱們也限制來每一個渲染引擎進程訪問其餘渲染引擎進程或者系統的權限。這樣在某種程度上就可讓瀏覽器受益於內存保護對操做系統的訪問權限。架構

咱們把運行UI、管理tab和插件進程的主進程稱爲「browser process」或者「broswer」。一樣地,具體的tab進程被稱爲「render process」或者「renderer」。renderer用Blink這個開源佈局引擎來解析HTML佈局。
arch.png佈局

管理渲染進程

每一個渲染進程都有一個全局的RenderProcess對象來管理與父browser進程的通訊,而且維護全局狀態。browser維護每一個渲染進程對應的RenderProcessHost,來管理browser狀態和渲染器的通訊。browser和renderers經過Chromium IPC系統進行通訊。性能

管理視圖

每一個渲染進程都有一個或者更多的RenderView對象,由RenderProcess管理,對應每一個tab的內容。對應的RenderProcessHost維護一個RenderViewHost對應每一個renderer的視圖。每一個視圖都被分配到一個ID來在同一個renderer裏區分多個view。這些ID在同一個renderer裏都是惟一的,可是在browser裏面不必定惟一,因此識別一個view同時須要RenderProcessHost和view ID。browser和某個具體的tab內容之間經過RenderViewHost對象,經過RenderProcessHost給RenderProcess 再定位到RenderView發送信息來進行通訊。spa

組件和接口

在渲染進程中:操作系統

  • RenderProcess處理IPC和browser進程中對應RenderProcessHost之間的通訊。每一個渲染進程中都明確地有一個RenderProcess對象。這就是browser ↔ renderer之間通訊的方式。
  • RenderView對象和browser進程中對應的RenderProcessHost進行通訊(經過RenderProcess),和咱們嵌入式的WebKit層。這個對象表明來一個web頁面的內容或者一個彈出的窗口。

在瀏覽器進程中:插件

  • Browser對象表明一個頂層的瀏覽器窗口
  • RenderProcessHost對象表明瀏覽器側的一個browser ↔ renderer通訊IPC鏈接。每一個渲染進程和瀏覽器進程之間都有一個RenderProcessHost對象。
  • RenderViewHost對象包含了和遠端RenderView之間的通訊,RenderWidgetHost處理輸入並繪製瀏覽器中的RenderWidget

內部更多詳細的工做原理能夠,能夠查看 How Chromium displays web pages)設計文檔

共享渲染進程

一般,每一個新的窗口或者tab都會在一個新的進程中打開。瀏覽器會打開一個新的進程而且建立一個單獨的RenderView。
可是有的時候,在tab和window之間共享渲染進程也是必要的。一個web飲用會打開一個新的窗口而且但願能同步的進行通訊,好比,在Javascript中使用window.open。在這種狀況下,當咱們建立一個新的window或者tab的時候,咱們就須要重複利用以前window已經打開過的進程。當進程數太多的時候咱們也有一些策略來分配已經打開的渲染進程給新的tab,或者若是這個用戶已經有打開過這個域名下的頁面建立的進程的時候。這個策略在Process Models中。

檢測crash或者故障的renderer

每一個和browser進程通訊的IPC鏈接都會監聽process handler。若是這些handler收到消息,renderer進程有crash,那麼這些tab就會被通知到crash。當前,咱們會展現一個「sad tab」到屏幕上來告訴用戶渲染進程crash了。這個頁面能夠經過按下刷新按鈕從新加載。這個時候,咱們也會通知沒有進程了,須要從新建立一個進程。

渲染沙箱

針對一個獨立的進程,咱們經過沙箱去限制訪問系統資源的權限。好比,咱們能夠經過父browser進程來保證渲染器只能訪問網絡。一樣的,咱們也能夠用操做系統內置的權限來限制它訪問文件系統的權限。
除了限制渲染器訪問文件系統和網絡的權限,咱們還能夠限制訪問用戶展現相關的權限。咱們運行渲染進程在一個用戶不可見的獨立Windows Desktop上。這防止了渲染進程打開一個新的window或者採集按鍵。

回收內存

讓渲染器在一個獨立的進程中運行,很天然的就會給隱藏的tab更低一點的優先級。一般,被下降內存的進程會自動地把內存分配到一個「可用內存」的池子裏。在低內存模式下,Windows會在要切換到高優先級模塊內存以前把這些內存交換到硬盤上,來使用戶可見的程序能更快的響應。咱們能夠應用一樣的策略到隱藏的tab裏。當一個渲染進程沒有最高優先級的tab時,須要時咱們能夠把這個進程的「working set」大小從系統內存先釋放到硬盤上。由於咱們發現減小工做區域大小也會下降用戶從2個tab之間切換的切換性能。可是當用戶有足夠的內存來運行他們的程序的時候就不會通知這個進程:Windows只有在確實須要的時候纔會回收這些數據,因此當有足夠的內存時不會有性能的損失。

插件和擴展

Firefox風格的NPAPI插件運行在他們本身的進程裏,和renderer分離開,詳細的描述在plugin architecture裏。
site isolation項目提供了renderer之間更多的隔離,包括了Chrome的HTML/Javascript在獨立進程中的上下文擴展。

相關文章
相關標籤/搜索