瀏覽器這個領域原先是Netscape Navigator的天下(大家還記著嗎),後來微軟看著Netscape一夜躥紅怒不可遏,調兵遣將推出免費的IE。經過幾個回合的較量,Navigator不敵IE,落草成了寇。再後呢,IE一統天下,市場份額超過了90%。一旦壟斷形成,微軟就再也沒有前進的動力了。所以在很長的一段時間裡瀏覽器這個領域基本上是死水一潭,沒有任何創新。
真正意義上打響反IE第一槍的應該算是Firefox了,自推出以後不斷的攻城略地從IE的手裡搶市場。從技術上看,Firefox還是有一定建樹的。首先文件很小,下載和安裝都很快。另外,程序質量很高,比當時的IE更快捷更安全。還有,Firefox上的Add-on非常豐富,極大的增強和擴展了Firefox的功能。最後還應該指出的是Firefox支持其他OS,比如說Linux。
眼看著瀏覽器市場從一手遮天就演變到兩強爭霸了。沒想到Google又半路殺出,非要來個Threesome。現在呢,除了這三巨頭搶鏡以外,蘋果的Sarafi和Opera也攪了進來要分一杯羹。所以最近一段時間每個把星期就有一款瀏覽器推出新版本,並都會大言不慚的宣佈是「天下第一快」。
如果仔細一點看的話,就會發現這下一代瀏覽器爭奪的主戰場有三個
1)瀏覽器平臺的構架
2)JavaScript虛擬機
3)圖形圖像的硬件加速
這第一篇呢,就說說新一代瀏覽器在結構方面的變化。(由於時間有限,所以只能就最有代表性的IE, FF和Chrome來說了,其他瀏覽器就不贅述了)
新一代的瀏覽器,清一色的採用了所謂的多進程構架(Multi-process Architecture)。網上的朋友們都常說是Google的Chrome領風氣之先。但事實上呢,IE8的Beta版是最早採用這一構架上市的瀏覽器,從時間上看比Chrome還要早一些。所以呢Chrome首創這一構架的說法有些謬讚了。
有人會問了,怎麼一下子大家都玩「多進程構架」了,早幹嘛去了?原先的單進程構架怎麼了?
早先的瀏覽器呢,都算是一個「程序」,所以都是傳統的「單進程多線程」設計。也就是從任務管理器上看,只有一個進程(當然你可以啟動多個瀏覽器了搞出來多個進程,那不是我們要討論的問題)。瀏覽器內部呢,有很多的線程(thread),它們各司其職一同完成複雜的任務。這種設計線路中規中矩,程序開銷小,效率高,沒有什麼不對的地方。
問題出在了「人民群眾日益提高的文化物質要求」上。現在的瀏覽器已經不是一個傳統意義上的「程序」了,已經演化成了一個「平臺」。瀏覽器上搭載了無窮多的add-on,plug-in等等。人民群眾要在瀏覽器上看新聞,聽廣播,點高清視頻,玩3D遊戲。。。
除了瀏覽器的任務變得複雜以外,人們使用瀏覽器的習慣也變了很多。瀏覽器上開十個八個Tab同時光顧數家網站已經是家常便飯,並且可能瀏覽器開了就不帶關的,除非是出了問題。
開發瀏覽器的程序員們都漸漸的認識到,面對這樣的任務和要求,原先的單進程構架已經不再適用了。原因很簡單。因為單進程構架所以的東西都在一個進程裡運行,一個地方出問題可能就會使整個瀏覽器全部歇菜。瀏覽器Vendor不管多麼嚴格的控制程序質量,多麼苦心積慮的進行測試,還是不能解決這一問題。因為瀏覽器面對的一個「Open ended world」,你永遠無法控制第三方的add-on或是plug-in。這些程序如果出了問題,馬上就會波及瀏覽器。
於是乎,多進程的構架就成為了不二之選。說到底,這種構架的核心就是把瀏覽器的各大功能塊分開,運行在各自的進程裡面。一個地方出了問題只會是局部的影響,不會造成整個系統的崩潰?,F在的操作系統(Windows, Linux, Mac OS)中各個進程都運行在「保護模式」中,一個進程出了問題操作系統會將其的危害控制在該進程之內,不會對其他進程造成影響。這是瀏覽器採用多進程構架的基本前提。
這種構架為什麼以前不用呢?因為這種構架要比單一進程的那種程序複雜很多。多個進程間的通信要解決好,並且要把開銷壓縮到最小。就現在的技術水平而言,這個問題已不再是什麼大問題了。另外,現在大多的計算機都裝配有多個CPU(多核),內存也都比較大,多個線程一起運行的硬件資源也不再是一個制約因素了。
雖然在戰略上各個公司所見略同,但是在戰術實施上還是相差甚遠的。Google的Chrome看起來似乎革命最徹底,FF好像只是現有技術的一點點改良,而微軟的IE呢,則是另闢蹊徑,又搞了一套。
先看最簡單的Firefox.
FF把所有的東西還是留在了主進程內。所以當你啟動FF的時候還只是一個進程。當進入到一個網站的時候,如果網站比較簡單,那麼FF自己就料理了,不會產生任何新的進程。如果這個網站要求Plug-in的支持,比如說Flash,那麼FF就生成一個進程(叫做plugin-container.exe),在這個進程裡運行Plug-in。如果你又開一個Tab去了又一家網站並且這個網站也需要Flash,那麼FF就會共用現有的這個plugin-container為兩家網站的網頁提供Flash服務。所以說呢,FF的進程數量很好計算,那就是一個主進程 + 零到多個個plugin-container。plugin-container的數量取決於運行的Plug-in的種類有多少。
有趣的是如果你離開了或是關閉那些需要plug-in的網站,FF並不銷毀plugin-container進程。這呢,算是程序設計中一個常見的手段,就是你一旦使用了某個功能的話,那麼很可能你還會再次使用。所以呢,那個plugin-container就給你留著,下回來的時候就是現成的,省事兒不是。但是呢,這種設計也有問題,因為plugin-container的數量只增加不減少,對用戶而言,FF的內存越佔越多。最後不得不把它幹掉從新再來。
好,再來看Chrome
Chrome的做法是一個主進程(稱為瀏覽器進程,就是我們看到的東西),1到N個渲染進程(Renderer進程),0-N個Plug-in進程(多少種plug-in就需要多少個plug-in進程,這點和FF一樣),0-N個add-on進程(如果你的Chrome有3個add-on,那麼就會多出三個相應的線程),一些服務進程(比如新的GPU process, Rundll32進程)。
對細節感興趣的朋友,可以用Chrome自帶的Task Manager去看看Chrome工作時界面之下後臺進程生生滅滅的過程,很有意思。Google的這款瀏覽器就像一個茶館一樣,門簾永遠在哪兒(主進程),客人們(Renderer進程)進進出出換了一茬又一茬。
Chrome的這種設計有兩個突出的優越性。一是瀏覽器職能劃分的很細,每一個功能體都在自己的進程中,一個進程的問題影響只是局部性的。第二,由於Renderer進程不停的產生銷毀,所以即使程序有memory leak或是memory fragmentation也不要緊,因為過不多久進程就走人了,新進程又會從頭再來,一切都是嶄新的。
有網上的大拿說,Google的進程模式是Per process per site,不是Per process per tab。其實這句話之對了一半。比說你你到西西河來,Chrome馬上生成一個Renderer進程來負責這個網站的Render工作(包括JavaScript的運行)。你點擊幾個link多出幾個Tab來,Chrome並沒有多出新的進程來。看起來那些大拿的話是對的。但是如果你手工增加一個Tab並敲入西西河的地址,只時候Chrome就會忘記已有的這個西西河Renderer進程,而重新在來一個。
和FF不同的是,如果一種plug-in沒人用的話,Chrome會保留它一會兒。如果過了這個時間段還是idle,那麼Chrome就將它回收了,如果在保留期間有什麼網站需要這種plug-in了,那麼就延長它的壽命讓它繼續工作。
OK,最後來看IE
IE的進程結構比較不直觀。從外觀上看,有些像Chrome的Per process per site(和Chrome一樣也不是那麼嚴格)。但是呢,IE不把Plug-in或是Add-on拿出去。除了主進程以外就是Renderer進程了,只有兩種類型,而不是Chrome那樣的五種類型。這個Renderer進程除了html, CSS, JavaScript任務之外,Add-on和plug-in的程序也在其中。所以說是一個heavy-duty的Renderer。
和Chrome不同的一點是,IE並不是急於創建或是銷毀Renderer進程,它試圖重新利用他們。比如你當前是在西西河,如果你在address bar輸入另外一個網站的地址離開西西河到別的網站的話,IE會重用當前這個Renderer進程。而Chrome呢,是重新為新的網站生成一個新的Renderer進程,然後馬上銷毀西西河的這個Renderer進程。
看到這裡大家肯定有些暈了,不禁會問「你囉哩叭嗦的說了半天,到底哪種方案最好?」
這個很難說了,要看情況。比如說現在正是2012年倫敦奧運會,你開了三個Tab同時看三場比賽(Tab可以扯到桌面上鋪開來看)。一個是中國轉播的乒乓球,一個是美國轉播的籃球,還有一個英國轉播的足球。每個網頁上呢是Flash轉播的高清視頻,另外還有HTML5技術提供的網友實時評論和場外花絮等等。
比方說,英國方面轉播的足球出了問題,造成了Flash崩潰。那麼用FF的用戶和Chrome一樣,什麼圖像都沒了(因為Flash進程是共用的)。但是三場球的實時評論和場外花絮還能看得到。IE用戶呢,情況不太一樣,乒乓球和籃球還能看道視頻,實時評論和場外花絮也完全正常,但是足球那個TAB就全歇菜了。
再比方說,美國網站HTML5提供的場外花絮部分出了問題,那麼FF用戶最慘,整個FF歇菜了,什麼都沒了。Chrome和IE的用戶一樣,乒乓球和足球還看著很好的,只不過是籃球那個Tab宕掉了。因為FF是用主進程來處理HTML5的,Chrome和IE都是獨立的Renderer進程處理HTML5,出了問題之影響那一個具體的Process,別的Tab一點沒事兒。
就我個人而言,有這麼幾點看法
1)FF的保護機理太過簡單了。主線程任務太重,那裡面一出問題整個瀏覽器就宕了。另外,Plug-in process重來不回收也是一個問題。
2)Chrome的進程顯然太多了。如果你裝了七八個個Add-on,再去幾個網站的話,那麼整個進程數可能就是十好幾個了。對於那些內存少並且less powerful的機器可能就會是一個問題了。不知道在手機平臺上Chrome瀏覽器是不是也用的同樣的策略。
3)IE的想法不錯,想把進程數量壓縮在一個適當的範圍內,不給OS太多麻煩。但是不把plug-in和add-on從Renderer進程分離出去,就每個Tab而言,保護程度和可靠性就自然下降了。在實踐中的具體效果還有待於檢驗。
三種瀏覽器的新一代Beta版本我都用過,似乎Chrome給end-user的感覺最好。那麼多進程間的通訊效果很好,進程不停的生成和銷毀也沒有任何停頓的感覺,界面上始終很流暢,很少有滯後感。(Chrome的程序員們本來開始是要用微軟的COM技術來進行進程間通訊的,但發現COM不能滿足他們對Async通訊的要求,於是就改用named pipe。雖然麻煩了一點,但看起來效果很不錯。不過呢,在Linux平臺上,又變成了Socket,不知道有什麼原因。)
待續。。。
關於構架,補充一點
IE從很早開始,就以一個ActiveX Control的形式提供給程序員,你可以在你的程序裡很容易的集成IE,或是根據你自己的需求定製一個IE瀏覽器。很早以前我和鐵手開玩笑,專門寫了一個小程序用來灌水。當時好像鐵手限制「口水帖」,不滿200字的帖子不接受。我的小程序呢就是檢查一下回帖的字數,不夠的話瞎胡添點廢話湊夠200字。
如果你在程序中使用WebBrowser Control,當前機器中安裝的IE就會被自動載入。下面兩個圖就是我剛寫的一個程序運行在兩臺機器上的結果。一個是IE8,一個是IE9。後者呢,擁有一切最新瀏覽器的功能(新的JavaScript Engine, HTML5硬件加速等等)
真正意義上打響反IE第一槍的應該算是Firefox了,自推出以後不斷的攻城略地從IE的手裡搶市場。從技術上看,Firefox還是有一定建樹的。首先文件很小,下載和安裝都很快。另外,程序質量很高,比當時的IE更快捷更安全。還有,Firefox上的Add-on非常豐富,極大的增強和擴展了Firefox的功能。最後還應該指出的是Firefox支持其他OS,比如說Linux。
眼看著瀏覽器市場從一手遮天就演變到兩強爭霸了。沒想到Google又半路殺出,非要來個Threesome。現在呢,除了這三巨頭搶鏡以外,蘋果的Sarafi和Opera也攪了進來要分一杯羹。所以最近一段時間每個把星期就有一款瀏覽器推出新版本,並都會大言不慚的宣佈是「天下第一快」。
如果仔細一點看的話,就會發現這下一代瀏覽器爭奪的主戰場有三個
1)瀏覽器平臺的構架
2)JavaScript虛擬機
3)圖形圖像的硬件加速
這第一篇呢,就說說新一代瀏覽器在結構方面的變化。(由於時間有限,所以只能就最有代表性的IE, FF和Chrome來說了,其他瀏覽器就不贅述了)
新一代的瀏覽器,清一色的採用了所謂的多進程構架(Multi-process Architecture)。網上的朋友們都常說是Google的Chrome領風氣之先。但事實上呢,IE8的Beta版是最早採用這一構架上市的瀏覽器,從時間上看比Chrome還要早一些。所以呢Chrome首創這一構架的說法有些謬讚了。
有人會問了,怎麼一下子大家都玩「多進程構架」了,早幹嘛去了?原先的單進程構架怎麼了?
早先的瀏覽器呢,都算是一個「程序」,所以都是傳統的「單進程多線程」設計。也就是從任務管理器上看,只有一個進程(當然你可以啟動多個瀏覽器了搞出來多個進程,那不是我們要討論的問題)。瀏覽器內部呢,有很多的線程(thread),它們各司其職一同完成複雜的任務。這種設計線路中規中矩,程序開銷小,效率高,沒有什麼不對的地方。
問題出在了「人民群眾日益提高的文化物質要求」上。現在的瀏覽器已經不是一個傳統意義上的「程序」了,已經演化成了一個「平臺」。瀏覽器上搭載了無窮多的add-on,plug-in等等。人民群眾要在瀏覽器上看新聞,聽廣播,點高清視頻,玩3D遊戲。。。
除了瀏覽器的任務變得複雜以外,人們使用瀏覽器的習慣也變了很多。瀏覽器上開十個八個Tab同時光顧數家網站已經是家常便飯,並且可能瀏覽器開了就不帶關的,除非是出了問題。
開發瀏覽器的程序員們都漸漸的認識到,面對這樣的任務和要求,原先的單進程構架已經不再適用了。原因很簡單。因為單進程構架所以的東西都在一個進程裡運行,一個地方出問題可能就會使整個瀏覽器全部歇菜。瀏覽器Vendor不管多麼嚴格的控制程序質量,多麼苦心積慮的進行測試,還是不能解決這一問題。因為瀏覽器面對的一個「Open ended world」,你永遠無法控制第三方的add-on或是plug-in。這些程序如果出了問題,馬上就會波及瀏覽器。
於是乎,多進程的構架就成為了不二之選。說到底,這種構架的核心就是把瀏覽器的各大功能塊分開,運行在各自的進程裡面。一個地方出了問題只會是局部的影響,不會造成整個系統的崩潰?,F在的操作系統(Windows, Linux, Mac OS)中各個進程都運行在「保護模式」中,一個進程出了問題操作系統會將其的危害控制在該進程之內,不會對其他進程造成影響。這是瀏覽器採用多進程構架的基本前提。
這種構架為什麼以前不用呢?因為這種構架要比單一進程的那種程序複雜很多。多個進程間的通信要解決好,並且要把開銷壓縮到最小。就現在的技術水平而言,這個問題已不再是什麼大問題了。另外,現在大多的計算機都裝配有多個CPU(多核),內存也都比較大,多個線程一起運行的硬件資源也不再是一個制約因素了。
雖然在戰略上各個公司所見略同,但是在戰術實施上還是相差甚遠的。Google的Chrome看起來似乎革命最徹底,FF好像只是現有技術的一點點改良,而微軟的IE呢,則是另闢蹊徑,又搞了一套。
先看最簡單的Firefox.
FF把所有的東西還是留在了主進程內。所以當你啟動FF的時候還只是一個進程。當進入到一個網站的時候,如果網站比較簡單,那麼FF自己就料理了,不會產生任何新的進程。如果這個網站要求Plug-in的支持,比如說Flash,那麼FF就生成一個進程(叫做plugin-container.exe),在這個進程裡運行Plug-in。如果你又開一個Tab去了又一家網站並且這個網站也需要Flash,那麼FF就會共用現有的這個plugin-container為兩家網站的網頁提供Flash服務。所以說呢,FF的進程數量很好計算,那就是一個主進程 + 零到多個個plugin-container。plugin-container的數量取決於運行的Plug-in的種類有多少。
有趣的是如果你離開了或是關閉那些需要plug-in的網站,FF並不銷毀plugin-container進程。這呢,算是程序設計中一個常見的手段,就是你一旦使用了某個功能的話,那麼很可能你還會再次使用。所以呢,那個plugin-container就給你留著,下回來的時候就是現成的,省事兒不是。但是呢,這種設計也有問題,因為plugin-container的數量只增加不減少,對用戶而言,FF的內存越佔越多。最後不得不把它幹掉從新再來。
好,再來看Chrome
Chrome的做法是一個主進程(稱為瀏覽器進程,就是我們看到的東西),1到N個渲染進程(Renderer進程),0-N個Plug-in進程(多少種plug-in就需要多少個plug-in進程,這點和FF一樣),0-N個add-on進程(如果你的Chrome有3個add-on,那麼就會多出三個相應的線程),一些服務進程(比如新的GPU process, Rundll32進程)。
對細節感興趣的朋友,可以用Chrome自帶的Task Manager去看看Chrome工作時界面之下後臺進程生生滅滅的過程,很有意思。Google的這款瀏覽器就像一個茶館一樣,門簾永遠在哪兒(主進程),客人們(Renderer進程)進進出出換了一茬又一茬。
Chrome的這種設計有兩個突出的優越性。一是瀏覽器職能劃分的很細,每一個功能體都在自己的進程中,一個進程的問題影響只是局部性的。第二,由於Renderer進程不停的產生銷毀,所以即使程序有memory leak或是memory fragmentation也不要緊,因為過不多久進程就走人了,新進程又會從頭再來,一切都是嶄新的。
有網上的大拿說,Google的進程模式是Per process per site,不是Per process per tab。其實這句話之對了一半。比說你你到西西河來,Chrome馬上生成一個Renderer進程來負責這個網站的Render工作(包括JavaScript的運行)。你點擊幾個link多出幾個Tab來,Chrome並沒有多出新的進程來。看起來那些大拿的話是對的。但是如果你手工增加一個Tab並敲入西西河的地址,只時候Chrome就會忘記已有的這個西西河Renderer進程,而重新在來一個。
和FF不同的是,如果一種plug-in沒人用的話,Chrome會保留它一會兒。如果過了這個時間段還是idle,那麼Chrome就將它回收了,如果在保留期間有什麼網站需要這種plug-in了,那麼就延長它的壽命讓它繼續工作。
OK,最後來看IE
IE的進程結構比較不直觀。從外觀上看,有些像Chrome的Per process per site(和Chrome一樣也不是那麼嚴格)。但是呢,IE不把Plug-in或是Add-on拿出去。除了主進程以外就是Renderer進程了,只有兩種類型,而不是Chrome那樣的五種類型。這個Renderer進程除了html, CSS, JavaScript任務之外,Add-on和plug-in的程序也在其中。所以說是一個heavy-duty的Renderer。
和Chrome不同的一點是,IE並不是急於創建或是銷毀Renderer進程,它試圖重新利用他們。比如你當前是在西西河,如果你在address bar輸入另外一個網站的地址離開西西河到別的網站的話,IE會重用當前這個Renderer進程。而Chrome呢,是重新為新的網站生成一個新的Renderer進程,然後馬上銷毀西西河的這個Renderer進程。
看到這裡大家肯定有些暈了,不禁會問「你囉哩叭嗦的說了半天,到底哪種方案最好?」
這個很難說了,要看情況。比如說現在正是2012年倫敦奧運會,你開了三個Tab同時看三場比賽(Tab可以扯到桌面上鋪開來看)。一個是中國轉播的乒乓球,一個是美國轉播的籃球,還有一個英國轉播的足球。每個網頁上呢是Flash轉播的高清視頻,另外還有HTML5技術提供的網友實時評論和場外花絮等等。
比方說,英國方面轉播的足球出了問題,造成了Flash崩潰。那麼用FF的用戶和Chrome一樣,什麼圖像都沒了(因為Flash進程是共用的)。但是三場球的實時評論和場外花絮還能看得到。IE用戶呢,情況不太一樣,乒乓球和籃球還能看道視頻,實時評論和場外花絮也完全正常,但是足球那個TAB就全歇菜了。
再比方說,美國網站HTML5提供的場外花絮部分出了問題,那麼FF用戶最慘,整個FF歇菜了,什麼都沒了。Chrome和IE的用戶一樣,乒乓球和足球還看著很好的,只不過是籃球那個Tab宕掉了。因為FF是用主進程來處理HTML5的,Chrome和IE都是獨立的Renderer進程處理HTML5,出了問題之影響那一個具體的Process,別的Tab一點沒事兒。
就我個人而言,有這麼幾點看法
1)FF的保護機理太過簡單了。主線程任務太重,那裡面一出問題整個瀏覽器就宕了。另外,Plug-in process重來不回收也是一個問題。
2)Chrome的進程顯然太多了。如果你裝了七八個個Add-on,再去幾個網站的話,那麼整個進程數可能就是十好幾個了。對於那些內存少並且less powerful的機器可能就會是一個問題了。不知道在手機平臺上Chrome瀏覽器是不是也用的同樣的策略。
3)IE的想法不錯,想把進程數量壓縮在一個適當的範圍內,不給OS太多麻煩。但是不把plug-in和add-on從Renderer進程分離出去,就每個Tab而言,保護程度和可靠性就自然下降了。在實踐中的具體效果還有待於檢驗。
三種瀏覽器的新一代Beta版本我都用過,似乎Chrome給end-user的感覺最好。那麼多進程間的通訊效果很好,進程不停的生成和銷毀也沒有任何停頓的感覺,界面上始終很流暢,很少有滯後感。(Chrome的程序員們本來開始是要用微軟的COM技術來進行進程間通訊的,但發現COM不能滿足他們對Async通訊的要求,於是就改用named pipe。雖然麻煩了一點,但看起來效果很不錯。不過呢,在Linux平臺上,又變成了Socket,不知道有什麼原因。)
待續。。。
關於構架,補充一點
IE從很早開始,就以一個ActiveX Control的形式提供給程序員,你可以在你的程序裡很容易的集成IE,或是根據你自己的需求定製一個IE瀏覽器。很早以前我和鐵手開玩笑,專門寫了一個小程序用來灌水。當時好像鐵手限制「口水帖」,不滿200字的帖子不接受。我的小程序呢就是檢查一下回帖的字數,不夠的話瞎胡添點廢話湊夠200字。
如果你在程序中使用WebBrowser Control,當前機器中安裝的IE就會被自動載入。下面兩個圖就是我剛寫的一個程序運行在兩臺機器上的結果。一個是IE8,一個是IE9。後者呢,擁有一切最新瀏覽器的功能(新的JavaScript Engine, HTML5硬件加速等等)