日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

201509281125_《为什么移动app会很慢的深度分析(摘自司徒正美博客园文章)》

發(fā)布時(shí)間:2024/1/8 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 201509281125_《为什么移动app会很慢的深度分析(摘自司徒正美博客园文章)》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我寫過不少文章來討論為什么移動(dòng)Web應(yīng)用程序很慢,這也引起了不少的討論。但是不幸的是,這些討論沒有像我喜歡的那樣的基于事實(shí)。

所以我這篇文章的目地就是給這些問題帶來一些真正的證據(jù),而不是僅僅過來對(duì)罵。在這篇文章的中,你可以看到基準(zhǔn)測(cè)試(benchmark),可以看到專家的觀點(diǎn),你甚至可以看到非常誠(chéng)實(shí)(honest-to-God)的期刊文章。這篇文章有超過100個(gè)引用(不是開玩笑)。我不保證這篇文章能使你信服,甚至不保證這篇文章中的所有內(nèi)容都是正確的(在這樣大規(guī)模的文章中做到這一點(diǎn)幾乎是不可能的),但是我可以保證這是一篇關(guān)于許多iOS開發(fā)者都抱有的想法——移動(dòng)Web應(yīng)用很慢并且會(huì)在可預(yù)計(jì)的未來繼續(xù)如此——分析最完備和全面的文章。

現(xiàn)在我要警告你:這是一篇長(zhǎng)得嚇人的文章,差不多10000字。當(dāng)然,這是我故意的。我更喜歡好文章,而不是流行的文章。我嘗試使得這篇文章成為前者,同時(shí)宣揚(yáng)我認(rèn)同的風(fēng)氣:我們應(yīng)該鼓勵(lì)那些優(yōu)秀的、基于證據(jù)的、有趣的討論,不鼓勵(lì)那些詼諧、嘩眾取寵的評(píng)論。

我寫這篇的文章,在某種程度上是因?yàn)檫@是話題已經(jīng)到了一種爭(zhēng)論不休的地步。這不是另一篇爭(zhēng)論的文章,如果你想看到30秒左右的對(duì)罵:“真的!Web應(yīng)用很渣!”和“誰說的?Web程序挺好!”,那么這篇文章不適合你。另一方面,據(jù)我所知,到現(xiàn)在為止還沒有一個(gè)關(guān)于這個(gè)話題全面的、正式的、理性的討論。這篇文章中我嘗試去理性地討論這個(gè)激起千層浪的話題,盡管這可能是一個(gè)非常愚蠢的想法。這里我給自己辯護(hù)一下,我相信這個(gè)問題與那些本來可以更好地去討論卻沒有這樣做的人更有關(guān)系,而不是主題本身。

如果你想知道你那些原生代碼(native code)程序員朋友為什么在如今開放的網(wǎng)絡(luò)革命時(shí)期還在寫著萬惡的原生代碼,那就把本頁(yè)面加入書簽吧,給自己倒杯咖啡,找出一個(gè)下午的時(shí)間,找到一個(gè)舒服的椅子,然后我們就正式開始吧!

簡(jiǎn)單回顧

我上一篇博客中寫道:基于SunSpider的benchmark給出的數(shù)據(jù)可以看出當(dāng)今的移動(dòng)Web應(yīng)用很慢。

如果你認(rèn)為“Web應(yīng)用程序”就是“一個(gè)網(wǎng)頁(yè)加上一兩個(gè)按鈕”,那么你就可以讓那些花哨的benchmark——比如SunSpider——滾一邊去。但是如果你認(rèn)為“Web應(yīng)用程序”是指“簡(jiǎn)單的文字處理,簡(jiǎn)單的照片編輯,本地存儲(chǔ)和屏幕之間的切換動(dòng)畫”,那么除非你有想死的心,否則你永遠(yuǎn)不會(huì)愿意在ARM上寫Web應(yīng)用程序。

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

關(guān)于這個(gè)benchmark,主要三種主要的批評(píng):

1. JS比原生代碼要慢并不是什么新鮮事了,每個(gè)人在上第一學(xué)期的計(jì)算機(jī)基礎(chǔ)課時(shí)討論編譯型語言、JIT語言和解釋型語言是時(shí)候就知道了。問題是JS是不是慢到已經(jīng)成為你現(xiàn)在所寫軟件的大問題了,但是像這樣的benchmark并不能說明這個(gè)問題。

2. JS是很慢,這也的確是個(gè)問題,但是它在變得越來越快,所以在不久的未來,我們可以發(fā)現(xiàn)它不會(huì)那么慢了。所以大家一起學(xué)JS吧。

3. 我是Python/PHP/Ruby的服務(wù)器端的開發(fā)者,我不知道你們?cè)谡f什么。我知道我的服務(wù)器比你們的移動(dòng)設(shè)備快,但是如果我可以自信地保證使用真正的解釋型語言寫出支持上千個(gè)用戶的代碼,你們難道不能用一個(gè)帶有高性能JIT的語言寫出一個(gè)支持單個(gè)用戶的代碼嗎?真的有那么難嗎?

我有一個(gè)相當(dāng)高的目標(biāo),那就是反駁以上所有觀點(diǎn):是的,JS的確是慢到一定程度了;不,它在不久的未來不會(huì)變得有多快;不,你在服務(wù)器端的編程經(jīng)驗(yàn)不能正確地映射到移動(dòng)應(yīng)用中。

但是真正的問題在于,在所有討論這個(gè)話題的文章里面,基本上沒有人真正量化JS到底有多慢,或者提供某種真正有用的比較標(biāo)準(zhǔn)(相對(duì)于什么來說慢)。為了糾正這樣的情況,我在這篇文章中提出了三種(不僅僅是一種)比較JavaScript性能的辦法。我不會(huì)說“JS在什么情況下都慢”,而是真正量化它慢的程度,并且將它跟我們?cè)倨匠>幊探?jīng)驗(yàn)中的事情做對(duì)比,這樣你就可以根據(jù)這個(gè)結(jié)果結(jié)合自己的編程平臺(tái)做出決定,你也可以自己計(jì)算下看看是否JavaScript適合你自己的特定問題。

OK,但是JS的性能相比于原生代碼到底如何?

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

這是一個(gè)隨機(jī)的測(cè)試,正如日常生活中運(yùn)行的代碼一樣。如果你想要一個(gè)更好的實(shí)驗(yàn),可以自己運(yùn)行。我運(yùn)行這個(gè)實(shí)驗(yàn)還有另外一個(gè)原因,就是因?yàn)槠渌膶?shí)驗(yàn)都不存在LLVM和Nitro的對(duì)比。

在這個(gè)綜合的基準(zhǔn)測(cè)試中,LLVM一致地比Nitro快4.5倍:

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

但是1/5的性能對(duì)每個(gè)人來說還不夠好嗎?

在x86上是足夠好了。當(dāng)渲染一個(gè)電子表格的時(shí)候,CPU的計(jì)算能有多密集呢?其實(shí)并不是那么難。問題是,ARM不是x86。

根據(jù)GeekBench的結(jié)果,最新的MacBook Pro的性能是最新的iPhone性能的10倍。這其實(shí)不算太大問題——電子表格沒那么復(fù)雜。我們可以忍受10%的性能。但是我還要把它除以5?好家伙!我們現(xiàn)在只有桌面性能的2%了。

OK,但是文字處理到底有多難?我們可不可以用一個(gè)m68k芯片加上一個(gè)協(xié)處理器來搞定呢?這是一個(gè)可以回答的問題。你可能記不起來,Google Doc的實(shí)時(shí)協(xié)作之前事實(shí)上還不是一個(gè)正式的功能,后來他們進(jìn)行了大規(guī)模的重寫并且在2010年4月份加入到Google Doc里面。我們來看一下2010年瀏覽器的性能:

從圖中可以清晰地看到,iPhone 4S在Google Docs的實(shí)時(shí)協(xié)作方面完全不是桌面網(wǎng)頁(yè)瀏覽器的對(duì)手。當(dāng)然了,它還是可以跟IE8比上一比的。恭喜iPhone 4S,可喜可賀。

我們?cè)倏纯戳硗庖粋€(gè)正經(jīng)的JavaScript應(yīng)用:Google Wave。Wave從來沒有支持IE8,因?yàn)樗鼘?shí)在是太慢了。

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

注意,所有支持的瀏覽器的得分都低于1000,其中那個(gè)得分3800的因?yàn)樘硕缓雎粤恕Phone得分為2400。差不多和IE8一樣,太慢幾乎無法運(yùn)行。

這邊要說明的是,在移動(dòng)設(shè)備上實(shí)現(xiàn)實(shí)時(shí)協(xié)作是可能的,只是不太可能用JavaScript來實(shí)現(xiàn)。原生代碼和Web應(yīng)用的性能差距基本上和Firefox與IE8的性能差距差不多,這么大的差距足以影響正常的工作。

但是我感覺V8或者是現(xiàn)代JS已經(jīng)有了接近C的性能了?

這取決于你怎么理解“接近”了。如果你的C程序運(yùn)行了10ms,那么一個(gè)運(yùn)行50ms的JavaScript程序差不多是接近C的速度了。如果你的C程序運(yùn)行了10s,那么一個(gè)運(yùn)行了50s的JavaScript程序?qū)τ诖蠖鄶?shù)正常人來說很可能就不是接近C的速度了。

硬件角度

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

這個(gè)方法行不行得通取決于你是否相信摩爾定律,以及給每個(gè)芯片配置一個(gè)3盎司的電池是否可行。我不是一個(gè)硬件工程師,但是我曾經(jīng)為一家大型半導(dǎo)體公司工作過,那里的人告訴我說當(dāng)今硬件的性能基本上是制作工藝(process)起的作用。iPhone 5令人印象深刻的性能主要是因?yàn)槠湫酒に噺?5nm做到了32nm,減少了差不多1/3。但是如果想繼續(xù)這么做,蘋果就要達(dá)到22nm的工藝。

順便提一下,Intel22nm工藝的Atom處理器現(xiàn)在還沒上市。而且Intel不得不重新發(fā)明全新的半導(dǎo)體,畢竟原來的半導(dǎo)體在22nm級(jí)別已經(jīng)不適用了。他們會(huì)把工藝授權(quán)給ARM?再好好想想吧。如今22nm的產(chǎn)品少之又少,而且大部分被Intel掌控著。

事實(shí)上,ARM似乎已經(jīng)在著手在明年嘗試28nm了(看看A7),同時(shí)Intel正在嘗試22nm甚至在稍微晚些時(shí)候嘗試20nm。從純硬件的角度,我感覺具有x86級(jí)別性能的x86芯片很可能遠(yuǎn)遠(yuǎn)比具有x86性能的ARM芯片更早登錄智能手機(jī)市場(chǎng)。

看一個(gè)前Intel工程師給我發(fā)的郵件:

我是一個(gè)前Intel工程師,剛開始從事于移動(dòng)微處理器的工作,后來工作轉(zhuǎn)向了Atom處理器。無論如何,我有一個(gè)很偏激的觀點(diǎn),即x86從較大的核心轉(zhuǎn)向手機(jī)市場(chǎng)的難度遠(yuǎn)比ARM從頭開始設(shè)計(jì)技術(shù)細(xì)節(jié)以達(dá)到x86的性能級(jí)別的難度要低很多。

再看一個(gè)機(jī)器人領(lǐng)域的工程師給我發(fā)的郵件:

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

摩爾定律無論怎么說都可能是正確的,但是這需要整個(gè)移動(dòng)生態(tài)環(huán)境向x86環(huán)境轉(zhuǎn)變。這并非完全不可能,畢竟曾經(jīng)有人做過這樣的事。但那是在移動(dòng)處理器一年才賣出去100萬個(gè)的時(shí)候做的,不像現(xiàn)在,每個(gè)季度就可以賣出62萬個(gè)芯片。那個(gè)時(shí)候現(xiàn)成的虛擬化環(huán)境可以模擬出老架構(gòu)的60%的速度,而按照現(xiàn)在的研究來看,虛擬化系統(tǒng)上運(yùn)行優(yōu)化過的(O3)ARM代碼的速度已經(jīng)接近27%了。

如果你堅(jiān)信JavaScript的性能最終會(huì)到達(dá)一個(gè)合理的水平,那么硬件性能的提升絕對(duì)是最好的方式。要么Intel會(huì)在5年之內(nèi)開發(fā)出可行的iPhone芯片(這是有可能的),并且蘋果迅速轉(zhuǎn)向x86架構(gòu)(這是不太可能的),或者ARM能夠在未來的10年之內(nèi)得到性能的飛躍。但是在我看來,10年是一個(gè)很長(zhǎng)的時(shí)間,長(zhǎng)到足夠使某件事情可能成功。

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

軟件角度

這是一個(gè)很多優(yōu)秀軟件工程師犯錯(cuò)誤的地方。他們的思路是這樣的:JavaScript已經(jīng)變得更快了,并且它會(huì)變得更快。

這個(gè)觀點(diǎn)的前一部分是正確的,JavaScript的確變得快很多。但是我們現(xiàn)在已經(jīng)達(dá)到了JavaScript性能的頂點(diǎn)了,它不可能變得更快多少。

為什么?其實(shí)前一部分JavaScript的性能提升從某種程度上是硬件的原因,正如Jeff Atwood寫道:

我感覺從1996到2006之間JavaScript的性能變快了100倍。如果Web 2.0主要建立在JavaScript上的話,這很可能主要是因?yàn)槟柖伤鶐淼挠布阅芴嵘?/p>

如果我們把JS的性能提升總結(jié)為硬件性能提升的話,那么JS的已有的硬件性能提升不能預(yù)測(cè)未來的軟件性能提升。這就是為什么如果你相信JS會(huì)變得更快的話,最有可能的方式就是硬件變得更快,因?yàn)闅v史趨勢(shì)就是如此。

那么JIT如何呢?V8,Nitro/SFX,TraceMonkey/IonMonkey,Chakra等等?當(dāng)然,當(dāng)他們剛剛問世的時(shí)候,的確是很了不起的(但或許不像你認(rèn)為的那么了不起)。V8在2008年9月發(fā)布,我找到了一份差不多那個(gè)時(shí)候同期的Firefox 3.0.3,看看它的性能:

不要誤解我的意思,9倍的性能提升的確值得稱贊,畢竟這差不多是ARM和x86之間的性能差距了。即便如此,Chrome 8和Chrome 26之間的性能卻呈現(xiàn)出了水平線,因?yàn)樽詮?008開始,幾乎沒有什么重大的事情發(fā)生。其他瀏覽器廠商都已經(jīng)趕上來了,有些快有些慢,但是沒人真正提高過JavaScript的性能了。

JavaScript性能在提升嗎?

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

看不出差別?因?yàn)楦緵]有差別。JavaScript的性能最近根本沒有得到大的提升

如果你感覺現(xiàn)在的瀏覽器比2010年的瀏覽器跑的快的話,那很可能是因?yàn)槟阌辛艘慌_(tái)更快的電腦,但是這與Chrome的性能提升沒什么關(guān)系。

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

在我看來,在這個(gè)期間的性能提升還是太小,不足以支撐JS馬上就會(huì)足夠快這樣的論調(diào)。然而,要說我過分強(qiáng)調(diào)這個(gè)情況也沒錯(cuò),畢竟JavaScript的計(jì)算密集型操作的確在發(fā)生變化。但是推我來說,這些數(shù)字可以得出更大的推斷:這些性能提升的幅度還不足以在一定時(shí)間之內(nèi)使得JavaScript的速度趕上原生代碼。你需要性能達(dá)到2-9倍才能跟LLVM競(jìng)爭(zhēng)。這些提升是好的,但還不足夠好。更新結(jié)束

問題是,讓JavaScript采用JIT技術(shù)是一個(gè)60年前就有的想法,并且這60年來一直有人在研究。數(shù)以千計(jì)的你可能想到的編程語言對(duì)JIT的實(shí)現(xiàn)都證明這是一個(gè)好主意。但是既然我們已經(jīng)做到了,我們已經(jīng)用完了這個(gè)60年前的想法。伙計(jì)們,就是這樣的,表演結(jié)束了。或許我們可以在未來的60年之內(nèi)想到另一個(gè)好辦法。

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

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

這個(gè)結(jié)論或許對(duì)蘋果來說很容易得到,但是這個(gè)版本的Safari在NDA協(xié)議之下,所以沒有人能夠公開關(guān)于Safari性能的獨(dú)立參數(shù)。但是我可以僅僅根據(jù)現(xiàn)在已經(jīng)得到的信息來做一些分析。

我發(fā)現(xiàn)一些現(xiàn)象很有意思。第一、蘋果官方在公開的JSBench上的數(shù)據(jù)要比在他們?cè)谳^老的benchmark(如SunSpider)上給出的數(shù)據(jù)高出不少。現(xiàn)在JSBench背后有一些非常酷的名字,包括JavaScript之父Brenden Eich。但是和傳統(tǒng)的benchmark不一樣,JSBench的工作方式不會(huì)考慮整數(shù)和其它重要因素,它反而自動(dòng)為Amazon、Facebook和Twitter提供的內(nèi)容進(jìn)行優(yōu)化,而且根據(jù)它們提供的內(nèi)容來建立benchmark。

如果你在寫一個(gè)多數(shù)人用來瀏覽Facebook的瀏覽器,我可以理解用一個(gè)只測(cè)試Facebook性能的benchmark是很有用的。但是從另外的角度講,如果你在寫一個(gè)電子表格的程序,或者游戲,或是一個(gè)圖片過濾應(yīng)用,在我看來傳統(tǒng)的benchmark(注重整數(shù)運(yùn)算和md5哈希)會(huì)更能夠準(zhǔn)確地幫你預(yù)測(cè)出Facebook的分析代碼有多快。

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

圖中清楚地顯示出了Firefox的3.6版本比1.5版本在SunSpider的benchmark上性能提高了13倍。但是當(dāng)我們看它在amazon的benchmark上的性能表現(xiàn)時(shí),發(fā)現(xiàn)只有較謙虛的3倍的提升。更有意思的是,在過去的兩年時(shí)間,在amazon的benchmark上的性能提升其實(shí)是被夸大了。這意味著在SunSpider上做的一些優(yōu)化幾乎對(duì)amazon沒有太大作用。

在這篇文章中,JavaScript之父和Mozilla的首席架構(gòu)師之一曾公開承認(rèn)在過去的兩年之內(nèi)Amazon的JavaScript性能幾乎沒有提升,沒有發(fā)生過什么特別重要的事情。從這一點(diǎn)你也可以看出來,那些營(yíng)銷人員這些年都在過分夸大自己產(chǎn)品的性能。

他們繼續(xù)爭(zhēng)辯道:對(duì)于那些人們用來瀏覽Amazon網(wǎng)頁(yè)的瀏覽器來說,運(yùn)行Amazon的benchmark比運(yùn)行其它benchmark要更能準(zhǔn)確地預(yù)測(cè)出瀏覽器的性能(這是當(dāng)然了……),但是這些手段不會(huì)幫助你更好地寫出一個(gè)照片處理程序。

但是無論怎么說,從我可以看到的公開信息來看,蘋果聲稱的3.8倍的性能提升對(duì)你來說幾乎沒有什么太有用的東西。我可以告訴你,如果我有一些能夠反駁蘋果聲稱擊敗Chrome的benchmark的話,我將不被允許發(fā)布它們。

所以,我們總結(jié)一下這一節(jié),如果有一些人拿出一個(gè)柱狀圖來顯示網(wǎng)頁(yè)瀏覽器變得更快了,那并不能真正說明整個(gè)JS變得更快了。

但是還有一個(gè)更大的問題。

并非為性能而設(shè)計(jì)

下面這段話出自于Herb Sutter,現(xiàn)代C++中最著名的人物之一:

在過去的20年里,有一種很難根除的文化基因——只要的等下一代的(包括JIT和靜態(tài))編譯器出來,托管語言就會(huì)變得和原生語言一樣高效。是的,我完全希望C#和Java編譯器能夠不斷提高,包括JIT和類NGEN的靜態(tài)編譯器。但是,它們永遠(yuǎn)不會(huì)消除與原生代碼之間的效率差距,有兩個(gè)原因:一、JIT編譯不是主要問題。根本原因更為基本:托管語言在編程人員的開發(fā)效率(當(dāng)時(shí)的確是個(gè)問題)和程序的運(yùn)行效率之間從設(shè)計(jì)上做了故意的妥協(xié)。特別的,托管語言選擇選擇在所有的程序上添加額外的性能開銷,盡管你根本沒有用到一個(gè)特性,你都會(huì)受到這個(gè)特性帶來的額外的性能開銷。主要的例子是assumption/reliance、垃圾回收、虛擬運(yùn)行環(huán)境和元數(shù)據(jù)等功能在托管語言中是默認(rèn)打開。當(dāng)然還有其它的例子,比如托管代碼中函數(shù)默認(rèn)是virtual的,而C++代碼中的函數(shù)是默認(rèn)inline的。1盎司(譯注:12盎司=1磅)的內(nèi)聯(lián)阻止(inlining prevention)抵得上1磅的去虛擬化優(yōu)化(devirtualization optimization cure)。

下面這段話出自于Mono項(xiàng)目組的Miguel de Icaza,他是為數(shù)不多的“維護(hù)著一個(gè)主流JIT編譯器的人”。他說道:

關(guān)于主流托管語言(.NET、Java和JavaScript)的虛擬機(jī)之間的差異,有一個(gè)比較準(zhǔn)確的說法。托管語言的設(shè)計(jì)者在他們?cè)O(shè)計(jì)一門語言的過程中更傾向于安全性,而不是性能。

或者你可以找Alex Gaynor談一談,他負(fù)責(zé)維護(hù)和優(yōu)化Ruby的JIT編譯器,并且也為Python的JIT的優(yōu)化工作做出了貢獻(xiàn):

這是加在這些具有高生產(chǎn)力的動(dòng)態(tài)語言身上的詛咒。它們使得創(chuàng)建一個(gè)哈希表十分容易。這是一件非常好的事情。我認(rèn)為C程序員多數(shù)不太會(huì)使用哈希表,因?yàn)閷?duì)他們來說用哈希表實(shí)在是是一件痛苦的事情。原因有二:第一,你沒有一個(gè)內(nèi)置的哈希表;第二、當(dāng)你嘗試去使用的時(shí)候,你會(huì)左右碰壁。對(duì)比來看,Python、Ruby和JavaScript程序員都過度使用哈希表了,因?yàn)槭褂盟鼈儗?shí)在太容易了……所以大家都不在乎。

Google似乎意識(shí)到了JavaScript正面臨著性能的瓶頸:

復(fù)雜的Web應(yīng)用(這是Google比較擅長(zhǎng)的)在某些平臺(tái)上正在面臨著不小的掙扎,主要是因?yàn)檫@些應(yīng)用用到了一些不能被性能調(diào)優(yōu)的語言,這些語言有內(nèi)在的性能問題。

最后,我們聽聽權(quán)威人士的意見。我的一個(gè)讀者向我指出這段Brenden Eich的評(píng)論。正如你所知,他是JavaScript之父。

有一點(diǎn)Mike沒有強(qiáng)調(diào):得到一個(gè)更簡(jiǎn)單的語言。Lua比JS簡(jiǎn)單得多。這意味著你可以寫出一個(gè)簡(jiǎn)單的解釋器使得它跑得足夠快,同時(shí)能夠保持對(duì)trace-JIT代碼的尊重(這和JS不同)。

稍微下面一點(diǎn)又提到:

關(guān)于JS和Lua之間的差別,你可以說這完全是正確的設(shè)計(jì)和工程上的問題,但是內(nèi)在的復(fù)雜性區(qū)別還是很大。你當(dāng)然可以把較難的案例從熱路徑中刪除,但是他們也會(huì)因此付出代價(jià)。JS比Lua有更多的更難的案例。一個(gè)例子是:Lua(沒有顯式的元表使用)沒有像JS中的原型對(duì)象鏈(prototype object chain)的東西。

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

但是還有一個(gè)更更大的問題。

都是因?yàn)槔厥?/h2>

你可以發(fā)現(xiàn),CPU問題、CPU相關(guān)的benchmark以及所有有關(guān)CPU的設(shè)計(jì)決定,都只是故事的一半。故事的另一半是內(nèi)存。內(nèi)存問題現(xiàn)在看來是如此的巨大,大到使整個(gè)CPU的問題看上去都僅僅是冰山一角。實(shí)際上可以討論的是,所有關(guān)于CPU的討論都是轉(zhuǎn)移注意力的話題(red herring)。你接下來要閱讀的應(yīng)該會(huì)完全改變你對(duì)移動(dòng)設(shè)備軟件開發(fā)的理解。

2012年,蘋果做了一件非常奇怪的事情(當(dāng)然了,除非你是John Gruber,能夠看到它的到來)。他們把垃圾回收從OSX中除去了。真的,你可以去看看程序員指南。標(biāo)題右邊有一個(gè)大大的“不推薦(Not Recommended)”。如果你之前是Ruby、Python、JavaScript、Java、C#或是其它任何1990年代之后誕生的語言的開發(fā)者,這應(yīng)該會(huì)讓你感覺很奇怪。但是這很可能不會(huì)影響到你,因?yàn)槟愫芸赡懿辉贛ac下面使用ObjC,在HN點(diǎn)擊下一個(gè)鏈接。但是這仍然看上去很奇怪,畢竟GC一直被大家使用著,而且它的價(jià)值也得到了證明。為什么你要反對(duì)它呢?蘋果是這么說的:

我們十分堅(jiān)信ARC才是內(nèi)存管理的正確方式,所以我們決定使OSX上的垃圾回收變成過時(shí)的(deprecate)。——ession 101, Platforms Kickoff, 2012, ~01:13:50

這段話沒有告訴你的是,當(dāng)聽到這句話的時(shí)候,臺(tái)下的觀眾爆發(fā)出了熱烈的掌聲。OK,這就變得真的非常奇怪了。你是不是在告訴我有那么一個(gè)屋子里的程序員在為了垃圾回收之前的那種混亂的回歸鼓掌?你可以想象下如果Matz在RubyConf上宣布GC過時(shí)的時(shí)候整個(gè)會(huì)場(chǎng)的寂靜,幾乎一顆針掉在地上都聽得到聲音。而這群人卻因此而高興?太古怪了吧?

你應(yīng)該根據(jù)這些古怪的反應(yīng)發(fā)現(xiàn)一些你現(xiàn)在看不到但是卻是在真正發(fā)生的事情,而不是僅僅把這些事情歸結(jié)于這群人對(duì)于蘋果的狂熱。這些正在發(fā)生的事情就是我們下面就要討論的主題。

思維過程是這樣的:把一個(gè)工作得好好的垃圾回收器從一個(gè)語言中拿出來簡(jiǎn)直是瘋了吧?一個(gè)簡(jiǎn)答的解釋可能是ARC可能僅僅是蘋果為了給垃圾回收披上一層美麗新裝而創(chuàng)造的一個(gè)營(yíng)銷詞匯,所以這些開發(fā)者是為了這種升級(jí)而不是降級(jí)而鼓掌的。事實(shí)上,這就是很多iOS簇?fù)韨兊谋в械南敕ā?/p>

ARC不是一個(gè)垃圾收集器

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

這與和垃圾回收有類似名字的算法無關(guān)。它不是垃圾回收,他不是什么像垃圾回收的東西,它表現(xiàn)得一點(diǎn)都不像垃圾回收,它不會(huì)打亂任何保留周期,它沒有去回收任何東西,它甚至沒有去做掃描。OK,故事結(jié)束,它絕對(duì)不是垃圾回收。

因?yàn)檎降奈臋n還在NDA協(xié)議下,所以有很多傳言認(rèn)為這并不是真的(但是細(xì)則已經(jīng)可以看得到了,沒有任何借口了),而且很多博客都紛紛說這些不是真的。它是真的。不要再討論了。

垃圾回收不像你的經(jīng)驗(yàn)讓你感覺的那樣可行

這是蘋果在壓力之下給出的關(guān)于ARC和GC的說法:

在愿望清單的頂端上我們能為你們做的最重要的事情就是把垃圾回收帶到了iOS中,而這恰恰是我們最不應(yīng)該做的。不幸的是,垃圾回收給性能帶來了很多次優(yōu)的影響。你程序中的垃圾回收會(huì)使得你的內(nèi)存使用率變得很高,而且垃圾回收器經(jīng)常在不確定的時(shí)間點(diǎn)上被觸發(fā)而導(dǎo)致非常高的CPU使用率,從而打斷用戶正在做的事情。這就是為什么GC不適合在我們的移動(dòng)平臺(tái)上使用的原因。對(duì)比來看,帶有獲取和釋放(retain/release)的手動(dòng)內(nèi)存管理學(xué)起來比較難,坦率的講有些像痔瘡(譯注:這個(gè)翻譯可能不準(zhǔn)確,原文是pain in the ass)。但是它產(chǎn)生了更好更可預(yù)測(cè)的性能,這也是為什么我們選擇手動(dòng)內(nèi)存管理作為我們內(nèi)存管理策略的基礎(chǔ)的原因。因?yàn)樵谕饷嬲鎸?shí)的世界,高性能以及用戶體驗(yàn)的連續(xù)性是我們的用戶最看重的。(譯注:在蘋果看來,用戶體驗(yàn)要比開發(fā)者體驗(yàn)重要。)~Session 300, Developer Tools Kickoff, 2011, 00:47:49

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

1. 這可能會(huì)直接影響你整個(gè)職業(yè)生涯對(duì)于垃圾回收語言給桌面和服務(wù)器上帶來影響的理解;

2. Windows Mobile、Andriod、Mono Touch以及所有其它移動(dòng)平臺(tái)上的GC似乎都可以挺好地工作。

所以讓我們反過來看這個(gè)問題。

移動(dòng)平臺(tái)上的GC和桌面平臺(tái)上的GC不是同一回事

我知道你在想什么,你是一個(gè)有了N年開發(fā)經(jīng)驗(yàn)的Python程序員。現(xiàn)在是2013年了,垃圾回收完全可以解決問題。

這是一篇你想看到的文章,似乎問題并沒有解決:

如果你在這篇文章中其它什么都記不得,那么請(qǐng)記住這張圖。Y軸是垃圾回收所用的時(shí)間,X軸是“相對(duì)的內(nèi)存足跡”,相對(duì)于什么?相對(duì)于所需的最小內(nèi)存

這張圖想說明的是,“如果你有6倍以上你實(shí)際需要的內(nèi)存,那么使用垃圾回收是沒有問題的。但是如果你只有小于4倍你實(shí)際需要的內(nèi)存,那么災(zāi)難就要降臨了。”。但是不要相信我的話:

特別的,如果垃圾回收時(shí)系統(tǒng)擁有5倍于所需的內(nèi)存時(shí),它的運(yùn)行時(shí)性能差不多甚至是超過顯式內(nèi)存管理。但是,垃圾回收的性能在必須使用小堆(small heap)的情況下會(huì)出現(xiàn)急劇下降。如果有3倍于所需的內(nèi)存的話,它會(huì)跑得慢17%;如果只有2倍于所需的內(nèi)存的話,會(huì)慢70%。垃圾回收比物理內(nèi)存的換頁(yè)更容易受到內(nèi)存不足的影響。在這種情況下,我們所測(cè)試的所有垃圾回收器相對(duì)于手動(dòng)內(nèi)存管理都出現(xiàn)指數(shù)級(jí)的性能下降

現(xiàn)在我們?cè)賮肀容^一下顯式內(nèi)存管理的策略:

這些圖顯示,如果可用內(nèi)存在合理的范圍的情況下(但不足以容得下整個(gè)應(yīng)用),顯式內(nèi)存管理器都要比垃圾回收器快太多。比如說,pesudoJBB以63M的可用內(nèi)存運(yùn)行,Lea allocator在25s的時(shí)間內(nèi)完成運(yùn)行。在相同可用的內(nèi)存下運(yùn)行GenMS,花了超過10倍的時(shí)間來運(yùn)行(255s)。我們可以看到其它benchmark套件的相同趨勢(shì)。最值得一提的例子是213 javac和Lea allocator一起在36M的內(nèi)存下運(yùn)行,總體運(yùn)行時(shí)間是14s,而與GenMS一起運(yùn)行的情況下,運(yùn)行時(shí)間為211s,用了超過15倍的時(shí)間。

基本的事實(shí)是,在內(nèi)存受限的環(huán)境下垃圾回收性能的下降是指數(shù)級(jí)的。如果你在桌面電腦上寫Python或者JS程序的話,你整個(gè)的體驗(yàn)可能是這幅圖的右邊部分,你可以一輩子都體會(huì)不到垃圾回收帶來的性能問題。花點(diǎn)時(shí)間想想這幅圖的左邊部分,并且想想我們?cè)撊绾螒?yīng)對(duì)。

iOS上有多少可用內(nèi)存?

這一點(diǎn)很難準(zhǔn)確地描述。從iPhone 4到iPhone 5,這些設(shè)備上的物理內(nèi)存從512M到1G不等。但是其中很大一部分為系統(tǒng)預(yù)留了,還有更大的一部分為多任務(wù)處理預(yù)留了。所以唯一真正的方法是在不同的情況下進(jìn)行嘗試。Jan Ilavsky寫了一個(gè)非常有用的工具來完成這個(gè)任務(wù),但是貌似沒有人公開任何數(shù)據(jù)。但這一點(diǎn)現(xiàn)在已經(jīng)改變了。

現(xiàn)在,在一種“正常”的情況下(這一點(diǎn)很難具體說清楚是什么意思)進(jìn)行測(cè)試是非常重要的,因?yàn)槿绻阍谝慌_(tái)剛剛啟動(dòng)的機(jī)器上測(cè)試的話,你會(huì)得到更好的數(shù)據(jù),畢竟你的系統(tǒng)里面沒有Safari所打開的頁(yè)面。所以我就在“真實(shí)世界”的情況下拿出一些我公寓里的設(shè)備進(jìn)行本次benchmark。

你可以點(diǎn)擊進(jìn)去看看詳細(xì)的結(jié)果,大體上來說,在iPhone 4S上,當(dāng)你的程序使用了40M內(nèi)存的時(shí)候就會(huì)得到警告,而使用了213M內(nèi)存的時(shí)候,程序就會(huì)被殺死;在iPad 3上,使用400M左右時(shí)獲得警告,而使用550M左右的時(shí)候,程序被殺死。當(dāng)然了,這些也僅僅是數(shù)字而已,如果你的用戶在聽音樂或者在后臺(tái)跑一些程序,你可用的內(nèi)存會(huì)比我測(cè)試?yán)锩婵捎玫膬?nèi)存更少,這只是給你一個(gè)思路而已。這么多內(nèi)存看上去不少(213M應(yīng)該對(duì)每個(gè)人來說都足夠了,是吧?),但實(shí)際上這還不夠。舉個(gè)例子,iPhone 4S拍照時(shí)的分辨率為3264*2448,每張照片有超過30M的位圖數(shù)據(jù)。如果你在內(nèi)存里加載了2張照片你就會(huì)獲得警告,而如果加載了7張照片,程序就會(huì)被殺死。哦,你打算給你寫個(gè)循環(huán)在你的相冊(cè)中逐個(gè)處理?程序會(huì)被殺死。

還有一點(diǎn)需要十分注意:實(shí)際的情況下,一張照片可能存在于內(nèi)存的多個(gè)位置。比如說,如果你在拍照片,那么你在以下位置都有數(shù)據(jù):1) 你通過屏幕看到的攝像頭中的數(shù)據(jù),2) 攝像頭實(shí)際上拍到的照片數(shù)據(jù),3) 你嘗試寫到存儲(chǔ)卡中的壓縮JPEG緩沖數(shù)據(jù);4) 你準(zhǔn)備在下一個(gè)屏中顯示的數(shù)據(jù);5) 你準(zhǔn)備上傳到某個(gè)服務(wù)器中的數(shù)據(jù)。

在一些點(diǎn)上你會(huì)發(fā)現(xiàn),保留30M的緩沖區(qū)去顯示照片縮略圖是一個(gè)非常不好的想法,因?yàn)檫@樣你會(huì)引入更多的數(shù)據(jù):6) 用來保留下一屏顯示合適大小照片的緩存;7) 用于在后臺(tái)重新調(diào)整照片大小的緩存(在前臺(tái)做實(shí)在太慢了)。然后你發(fā)現(xiàn)你可能真正需要5個(gè)不同的大小,然后你的程序就不是一般的慢了,而是慢到讓人抓狂。在實(shí)際的應(yīng)用程序中,僅僅是處理一個(gè)照片就會(huì)遇到內(nèi)存的瓶頸并非罕見的事情。但是不要相信我說的話:

你能做的最糟糕的事情就是在內(nèi)存不充足的情況下在內(nèi)存中緩存圖片。當(dāng)一張圖片被畫成位圖或者顯示到屏幕上時(shí),我們就不得不把照片解碼為位圖。位圖的每個(gè)像素點(diǎn)為4字節(jié),無論原始圖片多大都是如此。每當(dāng)我們將它解碼一次,位圖就會(huì)綁定到圖片本身并且一直維持到這個(gè)對(duì)象生命周期結(jié)束之時(shí)。所以如果你把圖片加載到內(nèi)存而且曾經(jīng)顯示過一次,那你現(xiàn)在就會(huì)在內(nèi)存中保留整個(gè)位圖,直到你釋放它為止。所以永遠(yuǎn)不要把UIImage或者CGImage放到緩存中,除非你有一個(gè)非常明確(但愿是非常短期的)的目標(biāo)。- Session 318, iOS Performance In Depth, 2011

你甚至不要相信上面的話!你給自己分配的內(nèi)存其實(shí)只是冰山一角。下圖是蘋果一張幻燈片中給出的冰山的全圖。Session 242, iOS App Performance – Memory, 2012:

你可以從兩方面考慮這個(gè)問題。第一、在213M可用內(nèi)存的情況下,在iOS上寫一個(gè)照片處理程序比在桌面上寫一個(gè)要困難許多。第二,你在iOS上寫一個(gè)照片處理程序時(shí),你對(duì)內(nèi)存的需要會(huì)更多,因?yàn)槟愕淖烂娉绦驔]有一個(gè)可以放進(jìn)你口袋的攝像頭

我們可以看看另外一個(gè)例子:在iPad 3上,你要顯示一個(gè)視頻,這種照片的大小很可能比你電腦上的視頻要大不少(后面的高分辨率攝像頭,差不多2000-4000像素)。每一幀要顯示的就是一個(gè)12M的位圖。如果你對(duì)內(nèi)存的使用很節(jié)省的話,每一時(shí)刻你可以在內(nèi)存中保留45幀的未壓縮視頻或動(dòng)畫緩存,也就是在30fps的情況下每1.5s,在60fps的情況下0.75s。你想為一個(gè)全屏的動(dòng)畫預(yù)留緩存?應(yīng)用被殺死。值得指出的是,AirPlay的延遲是2s,所以對(duì)于任何多媒體類型的應(yīng)用,你幾乎是保證沒有足夠的內(nèi)存

這種情況下我們同樣面臨著和照片的多個(gè)數(shù)據(jù)拷貝差不多的問題。比如說,蘋果指出,“每一個(gè)UIView背后都有一個(gè)CALayer,而且只要CALayer存在于在這個(gè)層次中,對(duì)應(yīng)的圖片數(shù)據(jù)會(huì)一直保存在內(nèi)存中”。這意味著,很可能有許多中間的渲染數(shù)據(jù)的拷貝存在于內(nèi)存中。

還有剪切矩形和備份存儲(chǔ)這些可能會(huì)占用內(nèi)存的事情。這樣的數(shù)據(jù)處理架構(gòu)事實(shí)上是非常高效的,但是這帶來的代價(jià)是程序會(huì)盡可能地占用內(nèi)存。iOS不是為低內(nèi)存使用而設(shè)計(jì)的,它是為了快速運(yùn)行而設(shè)計(jì)的。這沒有和垃圾回收扯在一起。

我們同樣需要從兩個(gè)方面考慮問題。第一,你在一種內(nèi)存非常緊缺的情況下做出動(dòng)畫效果;第二、做出這樣超級(jí)高質(zhì)量的視頻和動(dòng)畫是需要極大的內(nèi)存的。而為了使得普通消費(fèi)者買得起消費(fèi)級(jí)別的、具有高攝像頭分辨率的產(chǎn)品,這種糟糕的、內(nèi)存受限的環(huán)境幾乎是必然的選擇。如果你想寫一個(gè)軟件來毫無壓力地播放視頻,那么你就得說服別人為了屏幕多花700美元,或者花500美元買一個(gè)iPad,它實(shí)際上已經(jīng)包含了一個(gè)內(nèi)置的電腦。

我們會(huì)獲得更多內(nèi)存嗎?(更新)

一些聰明的人說:“OK,你說了很多關(guān)于我們不會(huì)有更快的CPU。但是我們應(yīng)該回有更多的內(nèi)存吧?這正是桌面環(huán)境上發(fā)生的事情。”

這種理論的一個(gè)問題是,ARM平臺(tái)上的內(nèi)存就在處理器本身上,這被稱為package on package。所以在ARM上獲得更多的內(nèi)存幾乎和提高CPU性能是同一個(gè)問題,因?yàn)樗鼈儦w根結(jié)底是同一件事情:在CPU上集成更多的晶體管。內(nèi)存晶體管處理起來稍微容易一些,因?yàn)樗鼈兪墙y(tǒng)一的,所以不是那么難,但實(shí)際上也不是那么簡(jiǎn)單。

如果你看看iFixit的A6的照片,你會(huì)發(fā)現(xiàn)在CPU模具最表面的硅幾乎100%都是內(nèi)存。這意味著,如果你想擁有更多的內(nèi)存,你要么使得制作工藝更精細(xì),要么提高模具的大小。事實(shí)上,如果你把工藝的大小做歸一化處理,那么其實(shí)伴隨著每次內(nèi)存升級(jí),你的模具都在變得更大。

硅其實(shí)是一種不完美的材料,為了獲得更大的尺寸所付出的的代價(jià)是指數(shù)級(jí)增長(zhǎng)的。它們也很難維持較低的溫度,也很難放進(jìn)小設(shè)備中。它們和制作出更好的CPU的目標(biāo)是重復(fù)的,因?yàn)閮?nèi)存也面臨同樣的問題:CPU最上層的硅中需要放進(jìn)更多的晶體管。

搞不懂的是,面臨著PoP的這些問題,CPU廠商們繼續(xù)使用PoP的方式為系統(tǒng)提供內(nèi)存。我還沒有遇到任何ARM工程師能夠解釋這一點(diǎn)。或許以下的評(píng)論可能會(huì)幫助我們理解。我們有可能從PoP架構(gòu)轉(zhuǎn)向電腦中采用的分離內(nèi)存模塊,而且我感覺這比較可行。原因很簡(jiǎn)單,將內(nèi)存分為單獨(dú)的模塊比制造出更大的芯片和進(jìn)一步減小制作工藝對(duì)廠商來說毫無疑問成本是更低的。但是現(xiàn)在所有的廠商都在不停地嘗試提高制作工藝或者制作出更大的芯片,而不是把內(nèi)存模塊獨(dú)立出來。

然而,一些聰明的工程師曾經(jīng)給我發(fā)了郵件讓我填補(bǔ)了這方面的空白。

一個(gè)前Intel工程師說道:

PoP內(nèi)存模型可以大量減少內(nèi)存延遲,也可以減輕路由問題。但是我不是ARM工程師,也不確定這是否是全部的原因。

一個(gè)機(jī)器人學(xué)的工程師提到:

當(dāng)PoP內(nèi)存不夠用時(shí),“3D”內(nèi)存會(huì)提供足夠大的內(nèi)存:內(nèi)存芯片在生產(chǎn)的時(shí)候堆疊在一起,1G的RAM在同一層堆成10層向上,就像現(xiàn)在的硬件模型一樣。但是,這樣的開銷會(huì)很大,頻率和電壓都要相應(yīng)地降低使得電力消耗處于一個(gè)合理的水平。

移動(dòng)RAM的帶寬不會(huì)像最近提高得這么快了。帶寬被連接SoC和RAM包的總線的數(shù)量所限制。當(dāng)前RAM的總線多數(shù)使用的是高性能SoC的圓柱體表面。SoC的中間部分不能用來加入RAM總線,因?yàn)檫@些RAM包是層疊的。接下來的重大改變應(yīng)該回來自于將SoC和內(nèi)存放在一個(gè)單獨(dú)的、高度集成的包中,允許更小、更密集和大量的RAM總線(更大的帶寬),并給SoC設(shè)計(jì)和更低的RAM電壓帶來更多自由。根據(jù)這樣的設(shè)計(jì),更大的緩存也就可能成為現(xiàn)實(shí),因?yàn)镽AM可能用更高的帶寬放在SoC模具中。

但是Mono/Andriod/Windows Mobile平臺(tái)怎么解決這個(gè)問題呢?

這個(gè)問題事實(shí)上有兩個(gè)答案。第一個(gè)答案我們可以從圖中看出。如果你發(fā)現(xiàn)你有6倍于所需的內(nèi)存,垃圾回收其實(shí)是非常快的。舉個(gè)例子來說,如果你在寫一個(gè)文本編輯器,你可能可以用35M的內(nèi)存完成自己要做的所有事情,這是我的iPhone 4S會(huì)崩潰內(nèi)存上界的1/6。你可能在Mono上寫個(gè)文本編輯器,看到非常不錯(cuò)的性能,然后從這個(gè)例子中得出如下結(jié)論:垃圾回收十分適合這個(gè)任務(wù)。你是對(duì)的。

然而Xamarin框架在案例中有一個(gè)飛行器模擬器。很顯然的是,垃圾回收對(duì)于現(xiàn)實(shí)生活中的較大的應(yīng)用程序來說是不適合的。難道不是嗎?

你在開發(fā)和維護(hù)這個(gè)游戲時(shí)一定會(huì)遇到什么樣的問題?“性能一直是一個(gè)大問題,而且將持續(xù)是我們?cè)倏缙脚_(tái)中會(huì)遇到的最大的問題之一。最初的Windows Phone設(shè)備是非常慢的,我們不得不花很多時(shí)間來優(yōu)化程序,使得它達(dá)到一個(gè)體面的幀率。我們不僅僅在飛行模擬代碼上進(jìn)行優(yōu)化,而且在3D引擎上優(yōu)化。垃圾回收和GPU的弱點(diǎn)是最大的瓶頸。

程序員不約而同地聲稱垃圾回收是最大的瓶頸。當(dāng)你的案例中的人在抱怨的時(shí)候,那應(yīng)該是一個(gè)足夠引起你重視的線索了。但是Xamarin可能是一個(gè)局外人,我們還是來看看Andriod開發(fā)者怎么說的吧:

請(qǐng)記住下面是我在我的Galaxy Nexus上運(yùn)行的情況:無論怎么說都是性能非常不錯(cuò)的設(shè)備。但是看看渲染的時(shí)間!我在電腦上只要花幾百毫秒就可以渲染出這些圖片,可是在這臺(tái)手機(jī)上卻花了超過兩個(gè)數(shù)量級(jí)的時(shí)間。渲染“inferno”圖片超過6s?這簡(jiǎn)直是瘋了吧!要生成一副圖片,需要10-15倍的時(shí)間來運(yùn)行垃圾回收器。

另一個(gè)開發(fā)者:

如果你想在Andriod手機(jī)上為實(shí)時(shí)物體識(shí)別或者基于內(nèi)容的現(xiàn)實(shí)增強(qiáng)進(jìn)行對(duì)照相機(jī)圖片的處理,那么你很可能聽說過照相機(jī)預(yù)覽回調(diào)(Camera Preview Callback)的內(nèi)存問題。每次Java程序嘗試從系統(tǒng)獲取預(yù)覽圖片時(shí),系統(tǒng)就會(huì)創(chuàng)建一大塊新的內(nèi)存。當(dāng)垃圾回收器釋放這塊內(nèi)存時(shí),系統(tǒng)會(huì)卡住(freezes)100ms到200ms。如果系統(tǒng)在高負(fù)載的情況下,事情可能會(huì)變得非常糟糕(我曾經(jīng)在手機(jī)上做過物體識(shí)別——天吶,它幾乎把整個(gè)CPU都占用了)。如果你看過Andriod 1.6的源代碼你就會(huì)知道,這只是因?yàn)檫@個(gè)功能的包裝類(wrapper,用來包裝原生代碼)每次在一個(gè)新的幀可用時(shí)都會(huì)申請(qǐng)一個(gè)新的字節(jié)數(shù)組。當(dāng)然,內(nèi)置的原生代碼可以避免這個(gè)問題

或者,我還可以去看看Stack Overflow:

我負(fù)責(zé)在Andriod平臺(tái)上為Java寫的交互式游戲進(jìn)行性能調(diào)優(yōu)。很多時(shí)候,當(dāng)候垃圾回收開始工作會(huì)讓使得游戲的畫圖和交互功能發(fā)生打嗝。通常情況下這種打嗝持續(xù)不到1/10s,但有的時(shí)候在比較慢的設(shè)備上會(huì)長(zhǎng)達(dá)200ms。如果我在一個(gè)內(nèi)部循環(huán)中使用樹或者哈希表,我就就知道我要很小心,或者甚至不用Java標(biāo)準(zhǔn)的Collections框架,而是自己重新實(shí)現(xiàn)一個(gè),因?yàn)槲页袚?dān)不起垃圾回收帶來的額外開銷。

這是一個(gè)“接受的答案(accepted answer)”,有27個(gè)人贊同:

我也是Java手機(jī)游戲的開發(fā)者……避免垃圾回收(垃圾回收可能在某個(gè)點(diǎn)被出發(fā)從而大幅降低你游戲的性能)的最好方法就是不要再游戲的主循環(huán)中創(chuàng)建對(duì)象。實(shí)在沒有什么“簡(jiǎn)潔”的方式來處理這種問題,或許只有手動(dòng)追蹤這些對(duì)象了,真悲哀。這地也是目前大部分當(dāng)前移動(dòng)設(shè)備上性能優(yōu)良的Java游戲所采取的的方式。

我們來看看Facebook的Jon Perlow怎么看待這個(gè)問題:

對(duì)于開發(fā)流暢的安卓應(yīng)用來說,GC是一個(gè)非常大的性能問題。在Facebook,我們遇到的最大問題之一是GC會(huì)使得UI線程暫停。當(dāng)我們處理很多位圖數(shù)據(jù)時(shí),GC被觸發(fā)的頻率很高,而且難以避免。GC經(jīng)常導(dǎo)致掉幀的問題。即使GC只會(huì)阻塞UI線程幾毫秒,但這卻會(huì)嚴(yán)重影響原本需要16毫秒的幀渲染。

OK,我們?cè)俾犅犚粋€(gè)微軟MVP的說法:

通常情況下,你的代碼在33.33ms之內(nèi)就會(huì)完成執(zhí)行,從而使得30fps的幀率變得很不錯(cuò)。但是當(dāng)GC運(yùn)行的時(shí)候,它會(huì)占用那個(gè)時(shí)間。如果你的堆比較整潔和簡(jiǎn)單,那么GC一般可以運(yùn)行得不錯(cuò),不會(huì)對(duì)程序產(chǎn)生什么影響。但是讓一個(gè)簡(jiǎn)單的堆處于一個(gè)使GC可以快速運(yùn)行的情形是一件困難的編程任務(wù),它要求大量的計(jì)劃和/或程序重寫,即使是這樣也不是完全安全的(有時(shí)在一個(gè)復(fù)雜的、有很多玩意的游戲中你的堆里面有很多內(nèi)容)。更簡(jiǎn)單的方法是(假設(shè)你能這么做),在游戲過程中限制甚至是禁用內(nèi)存分配。

在有垃圾回收的情況下,在游戲中保證一定會(huì)贏的方法就是不要玩(作者的幽默,原文:the winning move is not play)。比這種哲理稍弱的一種形式如Andriod官方文檔中所說的:

對(duì)象創(chuàng)建永遠(yuǎn)不是免費(fèi)的。帶有線程級(jí)別內(nèi)存池的垃圾回收器使得內(nèi)存分配的成本變得稍微低一些,但是分配內(nèi)存永遠(yuǎn)比不分配內(nèi)存開銷大。因?yàn)楫?dāng)你在程序中分配對(duì)象時(shí),你會(huì)強(qiáng)制垃圾回收周期性地工作,從而使得用戶體驗(yàn)不是那么流暢。Andriod 2.3當(dāng)前引入的垃圾回收器有一些作用,但是要是應(yīng)該避免不必要的工作。因此,你應(yīng)該避免創(chuàng)建你不需要的對(duì)象實(shí)例。一般而言,盡可能不要?jiǎng)?chuàng)建短期臨時(shí)對(duì)象。越少的對(duì)象創(chuàng)建就意味著越低頻率的垃圾回收,從而提高用戶體驗(yàn)。

還不信?那讓我來問問一位真正從事垃圾回收工作的工程師,他為移動(dòng)設(shè)備實(shí)現(xiàn)垃圾回收器。

然而,WP7系統(tǒng)的手機(jī)CPU和內(nèi)存性能正在大幅度地提升。游戲和大型Silverlight應(yīng)用越來越多,這些程序會(huì)占用100M左右的內(nèi)存。隨著內(nèi)存的變得越來越大,很多對(duì)象擁有的引用會(huì)指數(shù)級(jí)地變多。在上面解釋的模式中,GC不得不去遍歷每個(gè)對(duì)象以及他們的引用,標(biāo)記它們,然后清理沒喲引用指向的內(nèi)存。所有GC的時(shí)間也大幅增加,并且成為這個(gè)應(yīng)用的工作集(workingset)的一個(gè)函數(shù)。這會(huì)在大型XN游戲中和SL應(yīng)用中導(dǎo)致程序卡住,體現(xiàn)在很長(zhǎng)的啟動(dòng)時(shí)間(因?yàn)镚C有可能在游戲啟動(dòng)的時(shí)候運(yùn)行)或者游戲過程中的小問題。

還是不信?Chrome有一個(gè)測(cè)量GC性能的benchmark。我們來看看它都干嘛了:

你可以看到很多GC導(dǎo)致的卡頓。當(dāng)然了,這是一個(gè)壓力測(cè)試,但還是能說明問題的。你真的愿意花幾秒時(shí)間來渲染一幀?你瘋了吧。

這么多引用,我才不會(huì)挨個(gè)看呢,直接告訴我結(jié)論就行了。

結(jié)論是:移動(dòng)設(shè)備上的內(nèi)存管理很難。iOS平臺(tái)的開發(fā)者已經(jīng)形成了一種文化,即手動(dòng)做大部分事情,讓編譯器做其它容易的部分。Andriod平臺(tái)形成的文化是,提高垃圾收集器的性能,但事實(shí)上開發(fā)者在實(shí)際開發(fā)中盡量避免使用它。這兩者的共同點(diǎn)是,大家在開發(fā)移動(dòng)應(yīng)用時(shí),開始越來越多地考慮內(nèi)存管理問題了。

當(dāng)JavaScript、Ruby或是Python開發(fā)者聽到“垃圾收集器”這個(gè)詞時(shí),他們習(xí)慣將它理解為“銀彈(silver bullet)垃圾收集器”,也就是“讓我不要讓我再考慮內(nèi)存問題的垃圾收集器”。但是移動(dòng)設(shè)備上根被沒有銀彈可言,每個(gè)人寫移動(dòng)應(yīng)用時(shí)都在考慮內(nèi)存問題,不管他們是否使用了垃圾收集器。獲得“銀彈”內(nèi)存管理方式的唯一方式就像我們?cè)谧烂姝h(huán)境上一樣,擁有10倍于程序?qū)嶋H需要內(nèi)存。

JavaScript的整個(gè)設(shè)計(jì)基于一個(gè)思想,即不要擔(dān)心內(nèi)存。看看Chromium開發(fā)者們?cè)趺凑f:

有沒有任何一種方式強(qiáng)制chrome的js引擎進(jìn)行垃圾回收?一般意義而言,沒有,這是從設(shè)計(jì)的角度就已經(jīng)確定了的。

ECMAScript規(guī)范沒有提到“分配(allocation)”這個(gè)詞,唯一與“內(nèi)存”相關(guān)的話題本質(zhì)上就是說整個(gè)主題都是“實(shí)現(xiàn)相關(guān)的(host-defined)”。

ECMA 6的維基頁(yè)面上有幾頁(yè)提案的草稿,歸根結(jié)底是說(不是開玩笑):

“垃圾回收器不可以回收那些程序需要繼續(xù)使用來完成正確執(zhí)行的內(nèi)存。所有不能從根節(jié)點(diǎn)傳遞遍歷到的對(duì)象都應(yīng)該最終被銷毀,防止程序因?yàn)閮?nèi)存耗盡而發(fā)生錯(cuò)誤。”

是的,他們的確在思考將這個(gè)需求規(guī)約:垃圾回收器不應(yīng)該回收那些不應(yīng)該被回收的東西,但是應(yīng)該回收那些需要被回收的。歡迎來到tautology club。但是下面這段話可能與我們的話題更相關(guān):

然而,并沒有規(guī)范說明單個(gè)對(duì)象占用多少內(nèi)存,也不太可能會(huì)有。因此當(dāng)任何程序在內(nèi)存耗盡的情況下,我們永遠(yuǎn)不會(huì)得到任何保證,所以任何準(zhǔn)確的、可觀察的下界。

用英語來說就是,JavaScript的思想(如果這算是一種思想的話)是你不應(yīng)該能夠觀察到系統(tǒng)內(nèi)存中的情況,想都不要想。這種思想和人們?cè)趯憣?shí)際的程序時(shí)候的想法簡(jiǎn)直是令人難以置信的背道而馳(so unbelievably out of touch),我甚至找不到正確的詞語來向你形容。我的意思是,在iOS的世界里,我們并不相信垃圾回收器,我們感覺Andriod開發(fā)者都瘋了(nuts)。我懷疑Andriod開發(fā)者會(huì)這么認(rèn)為:iOS開發(fā)者竟然會(huì)用手動(dòng)內(nèi)存管理,簡(jiǎn)直是瘋子。但是你知道這兩個(gè)水火不容的陣營(yíng)的人可以在哪件事情上達(dá)成共識(shí)嗎?那就是JavaScript開發(fā)者是真正的瘋子。你在移動(dòng)平臺(tái)上寫出一個(gè)有點(diǎn)意思的程序,而從來不關(guān)心系統(tǒng)內(nèi)存的分配和釋放,是絕對(duì)不可能的(absolutely zero chance)。絕對(duì)不可能。暫時(shí)把SunSpider的benchmark上的問題和CPU計(jì)算密集型的問題都拋開,我們可以得出這樣的結(jié)論:JavaScript,盡管現(xiàn)在存在著,是和移動(dòng)平臺(tái)軟件開發(fā)過程中絕對(duì)重要的思想,即永遠(yuǎn)要考慮內(nèi)存問題,從根本上是背道而馳的

只要人們想要人們想在移動(dòng)設(shè)備上開發(fā)各種視頻和照片處理程序(不像桌面電腦),只要移動(dòng)設(shè)備的內(nèi)存不是那么充足,這個(gè)問題就是非常棘手的。你在移動(dòng)設(shè)備上需要理性的、正式的內(nèi)存管理保證。而JavaScript從設(shè)計(jì)上來說是拒絕提供這些的

假設(shè)它能夠提供這些

現(xiàn)在你可能會(huì)問,“OK,桌面環(huán)境上的JS開發(fā)者不會(huì)移動(dòng)設(shè)備上的開發(fā)者遇到的問題。假設(shè)他們相信你說的,或者假設(shè)有一些知道這些問題的移動(dòng)開發(fā)者們根據(jù)JS重新設(shè)計(jì)一門語言。你感覺理論上他們可以做哪些事情?”

我不確定這是否是解決的,但是我可以在這個(gè)問題上放一些邊界。有另一群人曾經(jīng)嘗試在JS的基礎(chǔ)上設(shè)計(jì)一門適合移動(dòng)開發(fā)者的語言——RubyMotion。

這些人非常聰明,他們很了解Ruby。然后這些Ruby開發(fā)者認(rèn)為垃圾回收對(duì)于他們的語言來說是一個(gè)糟糕的想法。(GC倡導(dǎo)者們,你們看到我說的了嗎?)所以他們用了一種非常類似ARC的技術(shù)然后嫁接到語言當(dāng)中,然而卻沒有成功。

總結(jié):很多人正經(jīng)歷著由于RM-3或者其它難以辨別的問題所導(dǎo)致的內(nèi)存相關(guān)議題,我們可以看看他們?cè)趺凑f。

Ben Sheldon說:

不僅僅是你,我也面臨著內(nèi)存相關(guān)的程序崩潰(比如SIGSEGV和SIGBUS)生產(chǎn)環(huán)境下有10-20%的用戶遇到過這種情況。

有一些人懷疑這個(gè)問題是否易于處理:

我在最近的一次Motion Meetup會(huì)上提出關(guān)于RM-3的問題,Laurent和Watson都對(duì)此提出了自己的看法。Watson提到說,RM-3是最難修復(fù)的bug;Laurent說他嘗試了很多方法,但最終都沒有很好地解決這個(gè)問題。他們兩個(gè)人都是非常聰明和厲害的程序員,所以我相信他們說的話。

還有一些人懷疑編譯器理論上是否能夠解決這個(gè)問題:

很長(zhǎng)的一段時(shí)間內(nèi),我都認(rèn)為編譯器可以簡(jiǎn)單明確地處理程序塊,即靜態(tài)地分析程序塊內(nèi)部的內(nèi)容來判斷程序塊是否引用了這個(gè)程序塊外部的變量。我認(rèn)為,對(duì)于所有這些變量,編譯器可以在程序塊創(chuàng)建時(shí)獲取,在程序塊銷毀時(shí)釋放。這個(gè)過程吧這些變量的生命周期綁定到程序塊上(當(dāng)然,在某種情況下不是“完整的”生命周期)。有一個(gè)問題是instance_eval(譯注:Ruby中Object類的方法)。程序塊中的內(nèi)容或許是按你提前知道的方式使用的,但也有可能并不是你能夠提前知道的。

RubyMotion還有一個(gè)對(duì)立的問題:內(nèi)存泄露,而且它還有可能有其它問題。沒有人真正知道程序崩潰時(shí)內(nèi)存泄露有2個(gè)原因還是有200個(gè)原因。

所以不管怎么說,我們的結(jié)論是:一部分世界上最好的Ruby程序員專門為移動(dòng)設(shè)備開發(fā)設(shè)計(jì)了一種語言,他們?cè)O(shè)計(jì)了一個(gè)系統(tǒng),這個(gè)系統(tǒng)不僅會(huì)崩潰,而且還會(huì)內(nèi)存泄露,這些問題都是你可能會(huì)面臨到的。至今為止他們并沒有能夠處理這個(gè)問題,盡管他們已經(jīng)非常盡力了。對(duì)了,他們也表示他們“自己嘗試了不少次,但沒有能夠能夠找到一個(gè)好的并且能夠保持高性能的解決方案”。

我并不是說在JavaScript的基礎(chǔ)上創(chuàng)建一門具有較高內(nèi)存性能的語言是不可能的,我只是想說很多證據(jù)顯示這個(gè)問題會(huì)非常難。

更新:一個(gè)Rust語言的貢獻(xiàn)者提到:

我為Rust項(xiàng)目工作,我的主要目標(biāo)是實(shí)現(xiàn)零額外開銷的內(nèi)存安全。我們通過“@-boxes”(@T聲明的類型是任何類型T)的方式來支持通過GC處理的對(duì)象,而我們最近遇到的比較麻煩的事情是,GC觸碰到語言中的所有內(nèi)容。如果你想支持GC但卻不需要它,你就要非常仔細(xì)地設(shè)計(jì)你的怨言來支持零額外開銷的非GC指針。這不是一個(gè)簡(jiǎn)單的問題,我不認(rèn)為可以通過建立在JS的基礎(chǔ)上創(chuàng)建一門新語言來解決

OK,但是ASM.JS如何呢?

asm.js就比較有趣了,因?yàn)樗峁┝艘粋€(gè)JavaScript模型,但這個(gè)模型嚴(yán)格意義上不是建立在垃圾回收的基礎(chǔ)上的。所以從理論上講,使用正確的網(wǎng)頁(yè)瀏覽器,使用正確的API就可以了。問題是,“我們會(huì)得到正確的瀏覽器嗎?”

Mozilla顯然在這個(gè)概念上被出賣了,作為這個(gè)技術(shù)的作者,他們的實(shí)現(xiàn)今年晚些時(shí)候?qū)崿F(xiàn)了它。Chrome的反應(yīng)一直是含糊不清的,因?yàn)檫@個(gè)技術(shù)顯然和Google的其它提案,包括Dart和PNaC1有直接的競(jìng)爭(zhēng)關(guān)系。關(guān)于它有一個(gè)開發(fā)的bug清單,但是一個(gè)V8的黑客對(duì)此不滿意。至于Apple陣營(yíng),按照我現(xiàn)在看來,WebKit那群人對(duì)比完全保持沉默。IE?我從來就沒有抱任何希望。

無論如何,現(xiàn)在還不能說asm.js就是真正解決JavaScript問題,且能夠擊敗所有其它提案的方法。另外,如果它能做到,它真的不可能是JavaScript,畢竟它能夠可行的原因就是拋開了麻煩的垃圾回收器。所以它有可能和C/C++或者其它手動(dòng)管理內(nèi)存的語言的前端一起工作,但肯定不和我們現(xiàn)在知道并且喜歡的動(dòng)態(tài)語言一樣。

相對(duì)什么來說慢?

當(dāng)一些文章里面說“X慢”和“X不慢”的時(shí)候,一個(gè)問題是,沒有人真正說的清楚它們的參照系是什么。對(duì)于一個(gè)網(wǎng)頁(yè)瀏覽器開發(fā)者,和對(duì)于一個(gè)高性能集群的開發(fā)者,以及對(duì)于一個(gè)嵌入式系統(tǒng)的開發(fā)者,等等,“慢”的含義是不一樣的。既然我們已經(jīng)闖過了戰(zhàn)壕而且做了這么多benchmark,我可以給出你三個(gè)有用大致正確坐標(biāo)系

如果你是一個(gè)Web開發(fā)者,把iPhone 4S的Nitro當(dāng)做IE8來看,因?yàn)樗鼈兊腷enchmark成績(jī)差不多。這就給了你寫代碼時(shí)的正確坐標(biāo)系。寫代碼的時(shí)候應(yīng)該謹(jǐn)慎地使用JS,否則你會(huì)面臨一大堆平臺(tái)相關(guān)的性能問題要處理。有些應(yīng)用用JS來寫性價(jià)比是不高的,即使是流行的瀏覽器。

如果你是x86平臺(tái)上的C/C++開發(fā)者,把iPhone 4S的Web開發(fā)環(huán)境當(dāng)成只有桌面開發(fā)環(huán)境性能的1/50。其中1/10來自于ARM相對(duì)于x86的性能差距,1/5來自于JavaScript相對(duì)于C/C++的性能差距。在非JavaScript、性能為桌面環(huán)境1/10的情況下,仔細(xì)考慮正反面的因素。

如果你是Java、Ruby、Python或者C#開發(fā)者,按照以下方式去理解iPhone 4S的Web開發(fā)環(huán)境:它的性能是你電腦的1/10(ARM的因素),并且如果你的內(nèi)存使用超過35M,性能會(huì)指數(shù)級(jí)下降,這是由垃圾回收的工作方式?jīng)Q定的。還有,如果你的程序分配了超過213M的內(nèi)存,程序就會(huì)崩潰。注意,沒有人“從設(shè)計(jì)的角度”在運(yùn)行時(shí)刻給你這個(gè)信息。對(duì)了,人們都希望你在這種環(huán)境下寫出很耗內(nèi)存的照片處理和視頻應(yīng)用。

這是一篇非常長(zhǎng)的文章

下面是你應(yīng)該記得的內(nèi)容:

  • 2013年,用JavaScript寫的移動(dòng)應(yīng)用(如照片編輯等)實(shí)在是太慢了。
    • 比原生代碼慢5倍
    • 性能和IE差不多
    • 比x86平臺(tái)上的C/C++代碼慢50倍
    • 如果你的程序所有的內(nèi)存不超過35M,比服務(wù)器端的Java/Ruby/Python/C#慢10倍;如果內(nèi)存使用超過這個(gè)數(shù),性能開始指數(shù)級(jí)下降
  • 要使這個(gè)速度變得快一些,最可能的方式是讓硬件性能達(dá)到桌面水平的性能。從長(zhǎng)遠(yuǎn)來看這是可行的,但是看起來要等很長(zhǎng)時(shí)間。
  • 最近一段時(shí)間JavaScript語言本身并沒有變得更快,在JavaScript上工作的人認(rèn)為,在現(xiàn)有的語言和API下,它永遠(yuǎn)不會(huì)向原生代碼那么快。
  • 垃圾回收在內(nèi)存受限的環(huán)境下會(huì)呈現(xiàn)指數(shù)級(jí)的性能下降,這一點(diǎn)比桌面和服務(wù)器級(jí)別的情況差很多。
  • 任何能干的移動(dòng)開發(fā)者都花很多時(shí)間來為目標(biāo)設(shè)備考慮內(nèi)存性能問題,不管他們是否使用具有GC的環(huán)境。
  • 當(dāng)前的JavaScript,從本質(zhì)上是和允許程序?yàn)槟繕?biāo)設(shè)備考慮內(nèi)存性能問題這一點(diǎn)背道而馳的。
  • 如果JavaScript的工作者們意識(shí)到這問題并且做出改變,允許開發(fā)者考慮內(nèi)存問題,經(jīng)驗(yàn)表明這是技術(shù)上的難題。
  • asm.js讓人看到了一些希望,但是就算它能成功,它應(yīng)該是用了C/C++或者類似的“過時(shí)的”語言的前端,而不是像JavaScript這樣的前端。

讓我們提高爭(zhēng)論的層次

毫無疑問的一點(diǎn)是,我不久就將收到上百封郵件,這些郵件圈出我說的某句話,然后在不提供任何實(shí)際的證據(jù)(或者根本不能算是證據(jù))的情況下,指出我說得不對(duì)。或者說“我曾經(jīng)用JavaScript寫過一個(gè)文本編輯器,挺好”,或者說“有些我從來沒見過的人寫了一個(gè)飛行模擬器,但是從來沒有給我寫郵件說明他們遇到性能問題”,這些郵件我會(huì)一律刪除。

如果我們想要在移動(dòng)Web開發(fā)(或者是原生應(yīng)用,或者是任何其它事情)上取得一些進(jìn)展,我們都需要各種至少看上去有說服力(at least appear to have a plausible basis)的討論,包括benchmark、期刊以及編譯器作者們的引用等等。網(wǎng)上有很多HN關(guān)于“我曾經(jīng)寫了一個(gè)Web應(yīng)用,挺好”的評(píng)論,還有很多關(guān)于Facebook在知道他們將會(huì)知道現(xiàn)在應(yīng)該知道的東西的情況下(譯注:原味knowing what they would have known then what they could have known now,不知這樣翻譯對(duì)不對(duì)?)是選擇HTML5還是原生應(yīng)用是對(duì)是錯(cuò)的爭(zhēng)論(譯注:原文為bikeshedding,這是一個(gè)比較有意思的詞,意思是在還沒完成自行車車架還沒弄好的情況下就去討論車的顏色,意指過于關(guān)心細(xì)節(jié)和邊緣的問題,而忽視主要問題)。

對(duì)于我們來說,剩下來的任務(wù)是,明確地量化如何使得移動(dòng)Web和原生生態(tài)環(huán)境變得越來越好,接著為此做出一些事情。正如你所知,這也是一個(gè)軟件開發(fā)者應(yīng)該做的事情。

轉(zhuǎn)載于:https://www.cnblogs.com/beesky520/p/4843631.html

總結(jié)

以上是生活随笔為你收集整理的201509281125_《为什么移动app会很慢的深度分析(摘自司徒正美博客园文章)》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 精品人妻一区二区乱码 | 尤物影院在线观看 | 中文字幕无人区二 | 国产一区二区视频在线观看免费 | 国产在线视频福利 | 性一交一乱一色一免费无遮挡 | 伊人视频在线观看 | 99视频+国产日韩欧美 | 羞羞成人 | 国产老熟女一区二区三区 | 国产欧美日韩在线视频 | 国产精品一区二区麻豆 | 波多野结衣视频一区二区 | 日韩一卡二卡三卡四卡 | 久久久久久久久久一区二区 | 色福利视频 | 国产又粗又猛又爽又黄又 | 日韩欧美日韩 | 激情五月开心婷婷 | 国产美女精品人人做人人爽 | 亚洲系列中文字幕 | 91高清免费视频 | 一区二区三区在线观看 | 中文人妻熟妇乱又伦精品 | av在线播放国产 | 久久色婷婷| 亚洲永久免费av | 成人精品亚洲人成在线 | 黄色三级在线视频 | 久综合网| 欧美鲁鲁 | 亚洲在线视频 | 久久久999久久久 | 91精品国产福利在线观看 | 亚洲专区区免费 | av不卡免费在线 | 三级成人网 | www.久草.com| 成人午夜在线视频 | 两个人看的www视频免费完整版 | 亚洲精品少妇久久久久久 | 蜜桃tv在线观看 | 日韩av影片在线观看 | а√天堂www在线天堂小说 | 亚洲欧美亚洲 | 小视频在线看 | 国产日韩欧美综合 | 国语对白一区二区三区 | 欧美超逼视频 | 影音先锋男人天堂 | 亚洲淫片 | 古典武侠av | 中文一区二区在线 | 久久亚洲中文字幕无码 | 在线免费观看污 | 一级片免费看视频 | 国产精品无码电影 | 国产伦精品一区二区三区视频我 | 穿越异世荒淫h啪肉np文 | 国产一区二区三区在线视频 | 美女精品一区 | 91视色 | 久久无码精品丰满人妻 | 黄色污污视频 | 亚洲综合图片网 | 欧美激情免费观看 | 色综合久久网 | 国产伦精品一区二区三区视频黑人 | 中文无码日韩欧 | 香蕉久久国产av一区二区 | 亚洲国产成人精品女人 | 无码久久精品国产亚洲av影片 | 美女露胸软件 | 不卡视频一区 | 久久中文字幕国产 | 综合av| 亚洲自拍三区 | 97久久国产亚洲精品超碰热 | 亚洲AV无码一区二区伊人久久 | 色综合天天综合综合国产 | 国产资源网站 | 成人在线视频免费观看 | 亚洲激情图片区 | 动漫av网| 国产无遮掩| 玖玖色在线| 热久久中文 | 在线不卡日韩 | 捆绑裸体绳奴bdsm亚洲 | 久久6视频| 中文字幕免费视频观看 | 色桃视频 | 日韩一区二区三区在线观看 | 久久大片 | 欧美成人做爰大片免费看黄石 | 97公开免费视频 | 韩国美女福利视频 | 最污网站在线观看 | 在线黄色av网站 |