1. 程式人生 > >為什麼移動Web應用很慢?

為什麼移動Web應用很慢?

“I don’t often link to other articles, but this one is worth reading.”

  我不經常連結到其它文章,但是這篇文章的確值得一讀。

“He offers data (imagine!) to justly debunk many common memes and “easy answers” that routinely litter HN/Reddit/Slashdot comment threads.”

  這句話挺難翻譯的,大概意思應該是作者使用了確切的資料來支援自己的觀點,而不像其他很多人一樣只是隨意地發出毫無根據的評論。

“Don’t be distracted by the author’s viewpoint and emphasis on “iOS and Javascript” development – the article covers lots of important ground, including:

  • developing for ARM vs. x86;
  • developing for desktop vs. mobile;
  • managed vs. native code performance;
  • JIT issues vs. inherent language design tensions;
  • why garbage collection is not at all the panacea it’s often billed to be and often needs to be emphatically avoided (did you realize Apple already jettisoned GC?); and
  • as many of you know already, why if you’re serious about performance you’ll be seriously serious about memory usage and access patterns as a first-order issue.”

  不要被作者的觀點以及iOS和Javascript開發等字眼分散注意力——這篇文章包含了很多重要的基礎知識,包括:

  • ARM平臺程式設計和x86平臺程式設計比較;
  • 桌面環境程式設計和移動裝置程式設計比較;
  • 託管程式碼和原生程式碼效能比較;
  • JIT相關話題和語言內在的設計張力;
  • 為什麼垃圾回收不是宣傳中所說的萬能藥,而且經常被強調要避免使用(你意識到蘋果公司已經拋棄了GC嗎?);
  • 就像你們中的很多人已經知道的那樣,為什麼如果你很在乎效能,那麼你就應該認真嚴肅地將記憶體使用和訪問模式作為最優先需要考慮的問題。

既然Sutter大神如此推薦,我就好好把這篇文章看下來了,的確收穫頗豐,所以特意把這篇文章翻譯下來,一方面加深理解,另一方面跟大家分享。我翻譯的首要目標是可讀性和流暢性,並不一定拘泥於字眼;難以翻譯和習慣用英文表達的詞彙會保留。我可以保證理解作者95%以上的意思(畢竟是技術類文章),但是作者的一些幽默我很可能沒法傳神地翻譯出來,還請大家包涵。

(提示:這是一篇非常長的文章,認真讀下來可能需要一段時間。下面是正文翻譯。)

我寫過不少文章來討論為什麼移動Web應用程式很慢,這也引起了不少的討論。但是不幸的是,這些討論沒有像我喜歡的那樣的基於事實

所以我這篇文章的目地就是給這些問題帶來一些真正的證據,而不是僅僅過來對罵。在這篇文章的中,你可以看到基準測試(benchmark),可以看到專家的觀點,你甚至可以看到非常誠實(honest-to-God)的期刊文章。這篇文章有超過100個引用(不是開玩笑)。我不保證這篇文章能使你信服,甚至不保證這篇文章中的所有內容都是正確的(在這樣大規模的文章中做到這一點幾乎是不可能的),但是我可以保證這是一篇關於許多iOS開發者都抱有的想法——移動Web應用很慢並且會在可預計的未來繼續如此——分析最完備和全面的文章。

現在我要警告你:這是一篇長得嚇人的文章,差不多10000字。當然,這是我故意的。我更喜歡好文章,而不是流行的文章。我嘗試使得這篇文章成為前者,同時宣揚我認同的風氣:我們應該鼓勵那些優秀的、基於證據的、有趣的討論,不鼓勵那些詼諧、譁眾取寵的評論。

我寫這篇的文章,在某種程度上是因為這是話題已經到了一種爭論不休的地步。這不是另一篇爭論的文章,如果你想看到30秒左右的對罵:“真的!Web應用很渣!”和“誰說的?Web程式挺好!”,那麼這篇文章不適合你。另一方面,據我所知,到現在為止還沒有一個關於這個話題全面的、正式的、理性的討論。這篇文章中我嘗試去理性地討論這個激起千層浪的話題,儘管這可能是一個非常愚蠢的想法。這裡我給自己辯護一下,我相信這個問題與那些本來可以更好地去討論卻沒有這樣做的人更有關係,而不是主題本身。

如果你想知道你那些原生程式碼(native code)程式設計師朋友為什麼在如今開放的網路革命時期還在寫著萬惡的原生程式碼,那就把本頁面加入書籤吧,給自己倒杯咖啡,找出一個下午的時間,找到一個舒服的椅子,然後我們就正式開始吧!

簡單回顧

上一篇部落格中寫道:基於SunSpider的benchmark給出的資料可以看出當今的移動Web應用很慢。

如果你認為“Web應用程式”就是“一個網頁加上一兩個按鈕”,那麼你就可以讓那些花哨的benchmark——比如SunSpider——滾一邊去。但是如果你認為“Web應用程式”是指“簡單的文書處理,簡單的照片編輯,本地儲存和螢幕之間的切換動畫”,那麼除非你有想死的心,否則你永遠不會願意在ARM上寫Web應用程式。

你應該先讀一下那篇文章,但是我還是在這邊給你看下benchmark:

關於這個benchmark,主要三種主要的批評:

1. JS比原生程式碼要慢並不是什麼新鮮事了,每個人在上第一學期的計算機基礎課時討論編譯型語言、JIT語言和解釋型語言是時候就知道了。問題是JS是不是慢到已經成為你現在所寫軟體的大問題了,但是像這樣的benchmark並不能說明這個問題。

2. JS是很慢,這也的確是個問題,但是它在變得越來越快,所以在不久的未來,我們可以發現它不會那麼慢了。所以大家一起學JS吧。

3. 我是Python/PHP/Ruby的伺服器端的開發者,我不知道你們在說什麼。我知道我的伺服器比你們的移動裝置快,但是如果我可以自信地保證使用真正的解釋型語言寫出支援上千個使用者的程式碼,你們難道不能用一個帶有高效能JIT的語言寫出一個支援單個使用者的程式碼嗎?真的有那麼難嗎?

我有一個相當高的目標,那就是反駁以上所有觀點:是的,JS的確是慢到一定程度了;不,它在不久的未來不會變得有多快;不,你在伺服器端的程式設計經驗不能正確地對映到移動應用中。

但是真正的問題在於,在所有討論這個話題的文章裡面,基本上沒有人真正量化JS到底有多慢,或者提供某種真正有用的比較標準(相對於什麼來說慢)。為了糾正這樣的情況,我在這篇文章中提出了三種(不僅僅是一種)比較JavaScript效能的辦法。我不會說“JS在什麼情況下都慢”,而是真正量化它慢的程度,並且將它跟我們再平常程式設計經驗中的事情做對比,這樣你就可以根據這個結果結合自己的程式設計平臺做出決定,你也可以自己計算下看看是否JavaScript適合你自己的特定問題。

OK,但是JS的效能相比於原生程式碼到底如何?

這是一個好問題。為了回答這個問題,我從Benchmark Game中隨意抓取了一個基準測試。然後我找到了一個做同樣benchmark的較老的C程式(老到不像很多新程式有一些x86特性)。我在自己的iPhone 4S上分別測試Nitro和LLVM。所有的程式碼已經傳到了Github

這是一個隨機的測試,正如日常生活中執行的程式碼一樣。如果你想要一個更好的實驗,可以自己執行。我執行這個實驗還有另外一個原因,就是因為其它的實驗都不存在LLVM和Nitro的對比。

在這個綜合的基準測試中,LLVM一致地比Nitro快4.5倍:

Screen Shot 2013-05-14 at 5.32.06 AM

如果你在想“如果是計算密集型(CPU-bound)的功能,原生代碼比Nitro JS快多少呢”,那麼答案是差不多5倍。這個結果大致上和Benchmark Game在x86/GCC/V8上面的結果一致,那裡面的GCC/x86通常比V8/x86快2到9倍。所以結果大致上是正確的,無論是ARM還是x86。

但是1/5的效能對每個人來說還不夠好嗎?

在x86上是足夠好了。當渲染一個電子表格的時候,CPU的計算能有多密集呢?其實並不是那麼難。問題是,ARM不是x86。

根據GeekBench的結果,最新的MacBook Pro的效能是最新的iPhone效能的10倍。這其實不算太大問題——電子表格沒那麼複雜。我們可以忍受10%的效能。但是我還要把它除以5?好傢伙!我們現在只有桌面效能的2%了。

OK,但是文書處理到底有多難?我們可不可以用一個m68k晶片加上一個協處理器來搞定呢?這是一個可以回答的問題。你可能記不起來,Google Doc的實時協作之前事實上還不是一個正式的功能,後來他們進行了大規模的重寫並且在2010年4月份加入到Google Doc裡面。我們來看一下2010年瀏覽器的效能:

BrowserCompChart1 9-6-10[7]

從圖中可以清晰地看到,iPhone 4S在Google Docs的實時協作方面完全不是桌面網頁瀏覽器的對手。當然了,它還是可以跟IE8比上一比的。恭喜iPhone 4S,可喜可賀。

我們再看看另外一個正經的JavaScript應用:Google Wave。Wave從來沒有支援IE8,因為它實在是太慢了。

Notice how all these browsers bench faster than the iPhone 4S?

看到這些瀏覽器比iPhone 4S快多少了嗎?

注意,所有支援的瀏覽器的得分都低於1000,其中那個得分3800的因為太慢了而被忽略了。iPhone得分為2400。差不多和IE8一樣,太慢幾乎無法執行。

這邊要說明的是,在移動裝置上實現實時協作是可能的,只是不太可能用JavaScript來實現。原生程式碼和Web應用的效能差距基本上和Firefox與IE8的效能差距差不多,這麼大的差距足以影響正常的工作。

但是我感覺V8或者是現代JS已經有了接近C的效能了?

這取決於你怎麼理解“接近”了。如果你的C程式運行了10ms,那麼一個執行50ms的JavaScript程式差不多是接近C的速度了。如果你的C程式運行了10s,那麼一個運行了50s的JavaScript程式對於大多數正常人來說很可能就不是接近C的速度了。

硬體角度

1/5的速度在x86上是沒問題的,畢竟x86起點就比ARM快10倍,你還有很多上升空間。解決方案顯然是讓ARM變成10倍快,這樣就可以跟x86競爭了,然後我們就可以不用做任何工作就可以得到桌面環境的JS效能了。

這個方法行不行得通取決於你是否相信摩爾定律,以及給每個晶片配置一個3盎司的電池是否可行。我不是一個硬體工程師,但是我曾經為一家大型半導體公司工作過,那裡的人告訴我說當今硬體的效能基本上是製作工藝(process)起的作用。iPhone 5令人印象深刻的效能主要是因為其晶片工藝從45nm做到了32nm,減少了差不多1/3。但是如果想繼續這麼做,蘋果就要達到22nm的工藝。

順便提一下,Intel22nm工藝的Atom處理器現在還沒上市。而且Intel不得不重新發明全新的半導體,畢竟原來的半導體在22nm級別已經不適用了。他們會把工藝授權給ARM?再好好想想吧。如今22nm的產品少之又少,而且大部分被Intel掌控著。

事實上,ARM似乎已經在著手在明年嘗試28nm了(看看A7),同時Intel正在嘗試22nm甚至在稍微晚些時候嘗試20nm。從純硬體的角度,我感覺具有x86級別效能的x86晶片很可能遠遠比具有x86效能的ARM晶片更早登入智慧手機市場。

看一個前Intel工程師給我發的郵件:

我是一個前Intel工程師,剛開始從事於移動微處理器的工作,後來工作轉向了Atom處理器。無論如何,我有一個很偏激的觀點,即x86從較大的核心轉向手機市場的難度遠比ARM從頭開始設計技術細節以達到x86的效能級別的難度要低很多。

再看一個機器人領域的工程師給我發的郵件:

你說得非常對,這些(譯註:指的是ARM的發展)不會帶來多大的效能提升,Intel可能在近幾年之內就會有更高效能的移動處理器。事實上,移動處理器當前和桌面處理器面臨著同樣的問題,即工作頻率達到3GHz左右的時候,再提高時鐘速度就不可避免地使得功耗大大增加。這種情況同樣會發生在下一代工藝上,儘管IPC(Instruction per Clock,即CPU每一時鐘週期內所執行的指令多少)會得到一些提高(差不多10%-20%)。在面臨這種限制的情況下,桌面處理器開始向雙核和四核方向變化,但是移動處理器現在已經是雙核和四核了,所以想提高效能不是那麼容易。

摩爾定律無論怎麼說都可能是正確的,但是這需要整個移動生態環境向x86環境轉變。這並非完全不可能,畢竟曾經有人做過這樣的事。但那是在移動處理器一年才賣出去100萬個的時候做的,不像現在,每個季度就可以賣出6200萬個晶片。那個時候現成的虛擬化環境可以模擬出老架構的60%的速度,而按照現在的研究來看,虛擬化系統上執行優化過的(O3)ARM程式碼的速度已經接近27%了。

如果你堅信JavaScript的效能最終會到達一個合理的水平,那麼硬體效能的提升絕對是最好的方式。要麼Intel會在5年之內開發出可行的iPhone晶片(這是有可能的),並且蘋果迅速轉向x86架構(這是不太可能的),或者ARM能夠在未來的10年之內得到效能的飛躍。但是在我看來,10年是一個很長的時間,長到足夠使某件事情可能成功

恐怕我的硬體的知識只能分析到這裡了。我可以告訴你的是,如果你相信ARM可以在未來的5年之內填補與x86之間的效能差距,那麼第一步就是找到一個在ARM或者x86上工作的人(也就是真正懂硬體的人),讓他同意你的看法。我寫這篇文章之前,曾近諮詢過很多有很高資質的硬體工程師,他們所有人都拒絕公開發表這個觀點,這讓我感覺這個觀點不是很靠譜。

軟體角度

這是一個很多優秀軟體工程師犯錯誤的地方。他們的思路是這樣的:JavaScript已經變得更快了,並且它會變得更快。

這個觀點的前一部分是正確的,JavaScript的確變得快很多。但是我們現在已經達到了JavaScript效能的頂點了,它不可能變得更快多少。

為什麼?其實前一部分JavaScript的效能提升從某種程度上是硬體的原因,正如Jeff Atwood寫道:

我感覺從1996到2006之間JavaScript的效能變快了100倍。如果Web 2.0主要建立在JavaScript上的話,這很可能主要是因為摩爾定律所帶來的硬體效能提升。

如果我們把JS的效能提升總結為硬體效能提升的話,那麼JS的已有的硬體效能提升不能預測未來的軟體效能提升。這就是為什麼如果你相信JS會變得更快的話,最有可能的方式就是硬體變得更快,因為歷史趨勢就是如此。

那麼JIT如何呢?V8,Nitro/SFX,TraceMonkey/IonMonkey,Chakra等等?當然,當他們剛剛問世的時候,的確是很了不起的(但或許不像你認為的那麼了不起)。V8在2008年9月釋出,我找到了一份差不多那個時候同期的Firefox 3.0.3,看看它的效能:

Screen Shot 2013-05-14 at 6.41.48 PM

不要誤解我的意思,9倍的效能提升的確值得稱讚,畢竟這差不多是ARM和x86之間的效能差距了。即便如此,Chrome 8和Chrome 26之間的效能卻呈現出了水平線,因為自從2008開始,幾乎沒有什麼重大的事情發生。其他瀏覽器廠商都已經趕上來了,有些快有些慢,但是沒人真正提高過JavaScript的效能了。

JavaScript效能在提升嗎?

Screen Shot 2013-05-14 at 3.59.04 AM

這是我Mac上的Chrome 8(可執行的最早版本,2010年12月份的版本)和Chrome 26

看不出差別?因為根本沒有差別。JavaScript的效能最近根本沒有得到大的提升

如果你感覺現在的瀏覽器比2010年的瀏覽器跑的快的話,那很可能是因為你有了一臺更快的電腦,但是這與Chrome的效能提升沒什麼關係。

更新:有些聰明的人指出SunSpider現在不是一個好的benchmark(並且拒絕提供任何實際的數字或其它什麼)。為了能夠可以理性地討論,我在一些舊版本的Chrome上面執行Octane(一個Google的benchmark),的確顯示出了一些效能提升:

Octane on V8, 2011 to 2013

在我看來,在這個期間的效能提升還是太小,不足以支撐JS馬上就會足夠快這樣的論調。然而,要說我過分強調這個情況也沒錯,畢竟JavaScript的計算密集型操作的確在發生變化。但是推我來說,這些數字可以得出更大的推斷:這些效能提升的幅度還不足以在一定時間之內使得JavaScript的速度趕上原生程式碼。你需要效能達到2-9倍才能跟LLVM競爭。這些提升是好的,但還不足夠好。更新結束

問題是,讓JavaScript採用JIT技術是一個60年前就有的想法,並且這60年來一直有人在研究。數以千計的你可能想到的程式語言對JIT的實現都證明這是一個好主意。但是既然我們已經做到了,我們已經用完了這個60年前的想法。夥計們,就是這樣的,表演結束了。或許我們可以在未來的60年之內想到另一個好辦法。

但是Safari恐怕比以前要快吧?

Is Safari 7 3.8x faster than the other guys?

Safari 7 是不是比其它的瀏覽器快3.8倍?

這個結論或許對蘋果來說很容易得到,但是這個版本的Safari在NDA協議之下,所以沒有人能夠公開關於Safari效能的獨立引數。但是我可以僅僅根據現在已經得到的資訊來做一些分析。

我發現一些現象很有意思。第一、蘋果官方在公開的JSBench上的資料要比在他們在較老的benchmark(如SunSpider)上給出的資料高出不少。現在JSBench背後有一些非常酷的名字,包括JavaScript之父Brenden Eich。但是和傳統的benchmark不一樣,JSBench的工作方式並不是通過編寫大整數分解或類似的程式,它反而自動為Amazon、Facebook和Twitter提供的內容進行優化,而且根據它們提供的內容來建立benchmark。

如果你在寫一個多數人用來瀏覽Facebook的瀏覽器,我可以理解用一個只測試Facebook效能的benchmark是很有用的。但是從另外的角度講,如果你在寫一個電子表格的程式,或者遊戲,或是一個影象過濾應用,在我看來傳統的benchmark(注重整數運算和md5雜湊)會比分析Facebook效能的benchmark更能夠準確地幫你預測出程式碼有多快。

另一個重要的事實是,蘋果聲稱的在SunSpider上效能的提升並不能代表其它東西的提升,Eich et al在這篇提到蘋果所偏愛的benchmark的文章中寫道:

圖中清楚地顯示出了Firefox的3.6版本比1.5版本在SunSpider的benchmark上效能提高了13倍。但是當我們看它在amazon的benchmark上的效能表現時,發現只有較適度的3倍的提升。更有意思的是,在過去的兩年時間,在amazon的benchmark上的效能提升幾乎已經不存在了。這意味著在SunSpider上做的一些優化幾乎對amazon沒有太大作用。

在這篇文章中,JavaScript之父和Mozilla的首席架構師之一曾公開承認在過去的兩年之內Amazon的JavaScript效能幾乎沒有提升,沒有發生過什麼特別重要的事情。從這一點你也可以看出來,那些營銷人員這些年都在過分誇大自己產品的效能。

他們繼續爭辯道:對於那些人們用來瀏覽Amazon網頁的瀏覽器來說,執行Amazon的benchmark比執行其它benchmark要更能準確地預測出瀏覽器的效能(這是當然了……),但是這些手段不會幫助你更好地寫出一個照片處理程式。

但是無論怎麼說,從我可以看到的公開資訊來看,蘋果聲稱的3.8倍的效能提升對你來說幾乎沒有什麼太有用的東西。我可以告訴你,如果我有一些能夠反駁蘋果聲稱擊敗Chrome的benchmark的話,我將不被允許釋出它們。

所以,我們總結一下這一節,如果有一些人拿出一個柱狀圖來顯示網頁瀏覽器變得更快了,那並不能真正說明整個JS變得更快了。

但是還有一個更大的問題。

並非為效能而設計

JavaScript-the-good-parts

下面這段話出自於Herb Sutter,現代C++中最著名的人物之一:

在過去的20年裡,有一種很難根除的文化基因——只要等到下一代的(包括JIT和靜態)編譯器出來,託管語言就會變得和原生語言一樣高效。是的,我完全希望C#和Java編譯器能夠不斷提高,包括JIT和類NGEN的靜態編譯器。但是,它們永遠不會消除與原生程式碼之間的效率差距,有兩個原因:一、JIT編譯不是主要問題。根本原因更為基本:託管語言在程式設計人員的開發效率(當時的確是個問題)和程式的執行效率之間從設計上做了故意的妥協。特別的,託管語言選擇選擇在所有的程式上新增額外的效能開銷,儘管你根本沒有用到一個特性,你都會受到這個特性帶來的額外的效能開銷。主要的例子是assumption/reliance、垃圾回收、虛擬執行環境和元資料等功能在託管語言中是預設開啟。當然還有其它的例子,比如託管程式碼中函式預設是virtual的,而C++程式碼中的函式是預設inline的。1盎司(譯註:12盎司=1磅)的內聯阻止(inlining prevention)抵得上1磅的去虛擬化優化(devirtualization optimization cure)。

下面這段話出自於Mono專案組的Miguel de Icaza,他是為數不多的“維護著一個主流JIT編譯器的人”。他說道:

關於主流託管語言(.NET、Java和JavaScript)的虛擬機器之間的差異,有一個比較準確的說法。託管語言的設計者在他們設計一門語言的過程中更傾向於安全性,而不是效能。

或者你可以找Alex Gaynor談一談,他負責維護和優化Ruby的JIT編譯器,並且也為Python的JIT的優化工作做出了貢獻:

這是加在這些具有高生產力的動態語言身上的詛咒。它們使得建立一個雜湊表十分容易。這是一件非常好的事情。我認為C程式設計師多數不太會使用雜湊表,因為對他們來說用雜湊表實在是是一件痛苦的事情。原因有二:第一,你沒有一個內建的雜湊表;第二、當你嘗試去使用的時候,你會左右碰壁。對比來看,Python、Ruby和JavaScript程式設計師都過度使用雜湊表了,因為使用它們實在太容易了……所以大家都不在乎。

Google似乎意識到了JavaScript正面臨著效能的瓶頸:

複雜的Web應用(這是Google比較擅長的)在某些平臺上正在面臨著不小的掙扎,主要是因為這些應用用到了一些不能被效能調優的語言,這些語言有內在的效能問題。

最後,我們聽聽權威人士的意見。我的一個讀者向我指出這段Brenden Eich的評論。正如你所知,他是JavaScript之父。

有一點Mike沒有強調:得到一個更簡單的語言。Lua比JS簡單得多。這意味著你可以寫出一個簡單的直譯器使得它跑得足夠快,同時能夠保持對trace-JIT程式碼的尊重(這和JS不同)。

稍微下面一點又提到:

關於JS和Lua之間的差別,你可以說這完全是正確的設計和工程上的問題,但是內在的複雜性區別還是很大。你當然可以把較難的案例從熱路徑中刪除,但是他們也會因此付出代價。JS比Lua有更多的更難的案例。一個例子是:Lua(沒有顯式的元表使用)沒有像JS中的原型物件鏈(prototype object chain)的東西。

在這些真正從事相關工作的人當中,持有JS或者是其它動態語言能夠趕上C語言效能這個觀點的,只佔極少數(very much the minority)。到處都有和主流想法不同的人,所以根本無法沒有什麼辦法能夠達到真正的一致。但是,從語言的角度說到JIT語言是否能夠趕上原生語言的效率,他們給出的答案都是“不,不可能,除非修改語言本身或者API”。

但是還有一個更更大的問題。

都是因為垃圾回收

你可以發現,CPU問題、CPU相關的benchmark以及所有有關CPU的設計決定,都只是故事的一半。故事的另一半是記憶體。記憶體問題現在看來是如此的巨大,大到使整個CPU的問題看上去都僅僅是冰山一角。實際上可以討論的是,所有關於CPU的討論都是轉移注意力的話題(red herring)。你接下來要閱讀的應該會完全改變你對移動裝置軟體開發的理解。

2012年,蘋果做了一件非常奇怪的事情(當然了,除非你是John Gruber,能夠看到它的到來)。他們把垃圾回收從OSX中除去了。真的,你可以去看看程式設計師指南。標題右邊有一個大大的“不推薦(Not Recommended)”。如果你之前是Ruby、Python、JavaScript、Java、C#或是其它任何1990年代之後誕生的語言的開發者,這應該會讓你感覺很奇怪。但是這很可能不會影響到你,因為你很可能不在Mac下面使用ObjC,在HN點選下一個連結。但是這仍然看上去很奇怪,畢竟GC一直被大家使用著,而且它的價值也得到了證明。為什麼你要反對它呢?蘋果是這麼說的:

我們十分堅信ARC才是記憶體管理的正確方式,所以我們決定使OSX上的垃圾回收變成過時的(deprecate)。——ession 101, Platforms Kickoff, 2012, ~01:13:50

這段話沒有告訴你的是,當聽到這句話的時候,臺下的觀眾爆發出了熱烈的掌聲。OK,這就變得真的非常奇怪了。你是不是在告訴我有那麼一個屋子裡的程式設計師在為了垃圾回收之前的那種混亂的迴歸鼓掌?你可以想象下如果Matz在RubyConf上宣佈GC過時的時候整個會場的寂靜,幾乎一顆針掉在地上都聽得到聲音。而這群人卻因此而高興?太古怪了吧?

你應該根據這些古怪的反應發現一些你現在看不到但是卻是在真正發生的事情,而不是僅僅把這些事情歸結於這群人對於蘋果的狂熱。這些正在發生的事情就是我們下面就要討論的主題。

思維過程是這樣的:把一個工作得好好的垃圾回收器從一個語言中拿出來簡直是瘋了吧?一個簡答的解釋可能是ARC可能僅僅是蘋果為了給垃圾回收披上一層美麗新裝而創造的一個營銷詞彙,所以這些開發者是為了這種升級而不是降級而鼓掌的。事實上,這就是很多iOS簇擁們的抱有的想法。

ARC不是一個垃圾收集器

所有的那些認為ARC是某種垃圾回收器的人,我想通過下面這個蘋果的幻燈片給你迎頭一擊(beat your face):

Screen Shot 2013-05-14 at 9.44.43 PM

這與和垃圾回收有類似名字的演算法無關。它不是垃圾回收,他不是什麼像垃圾回收的東西,它表現得一點都不像垃圾回收,它不會打亂任何保留週期,它沒有去回收任何東西,它甚至沒有去做掃描。OK,故事結束,它絕對不是垃圾回收。

因為正式的文件還在NDA協議下,所以有很多傳言認為這並不是真的(但是細則已經可以看得到了,沒有任何藉口了),而且很多部落格都紛紛說這些不是真的。它是真的。不要再討論了。

垃圾回收不像你的經驗讓你感覺的那樣可行

這是蘋果在壓力之下給出的關於ARC和GC的說法:

在願望清單的頂端上我們能為你們做的最重要的事情就是把垃圾回收帶到了iOS中,而這恰恰是我們最不應該做的。不幸的是,垃圾回收給效能帶來了很多次優的影響。你程式中的垃圾回收會使得你的記憶體使用率變得很高,而且垃圾回收器經常在不確定的時間點上被觸發而導致非常高的CPU使用率,從而打斷使用者正在做的事情。這就是為什麼GC不適合在我們的移動平臺上使用的原因。對比來看,帶有獲取和釋放(retain/release)的手動記憶體管理學起來比較難,坦率的講有些像痔瘡(譯註:這個翻譯可能不準確,原文是pain in the ass)。但是它產生了更好更可預測的效能,這也是為什麼我們選擇手動記憶體管理作為我們記憶體管理策略的基礎的原因。因為在外面真實的世界,高效能以及使用者體驗的連續性是我們的使用者最看重的。(譯註:在蘋果看來,使用者體驗要比開發者體驗重要。)~Session 300, Developer Tools Kickoff, 2011, 00:47:49

但是這還是完全瘋狂了,不是嗎?這只是開始:

1. 這可能會直接影響你整個職業生涯對於垃圾回收語言給桌面和伺服器上帶來影響的理解;

2. Windows Mobile、Andriod、Mono Touch以及所有其它移動平臺上的GC似乎都可以挺好地工作。

所以讓我們反過來看這個問題。

移動平臺上的GC和桌面平臺上的GC不是同一回事

我知道你在想什麼,你是一個有了N年開發經驗的Python程式設計師。現在是2013年了,垃圾