編譯 Android 工程的時(shí)候,意外遇到了這樣一個(gè)錯(cuò)誤:
com.android.dex.DexIndexOverflowException: Cannot merge new index 66739 into a non-jumbo instruction!
通過谷歌搜索這個(gè)問題售睹,發(fā)現(xiàn) StackOverflow 上面已經(jīng)有人遇到過相同的問題了:Application too big? Unable to execute dex: Cannot merge new index into a non-jumbo instruction幢痘。
大家給出的解釋是,一個(gè) dex 文件中至多容許存在 64K 個(gè)方法,超過這一限制悯辙,編譯器就會報(bào)錯(cuò)。
至于為什么 Android 中會有這樣一個(gè)詭異的數(shù)目限制迎吵,我猜測是因?yàn)?dalvik 中的某個(gè)計(jì)數(shù)器使用了 short
類型躲撰,因?yàn)?64K 剛好等于 65536。檢索了一番 dalvik 的源碼击费,發(fā)現(xiàn)確實(shí)如此拢蛋,下面是埋下了這個(gè)大坑的代碼:
// dalvik/dx/src/com/android/dx/merge/IndexMap.java
public IndexMap(Dex target, TableOfContents tableOfContents) {
...
public final short[] typeIds;
public final short[] protoIds;
public final short[] fieldIds;
public final short[] methodIds;
...
}
從代碼中可以看出,不只是 methodIds
不能超過 65536 個(gè)蔫巩,typeIds
谆棱、protoIds
以及 fieldIds
也都是如此。想必 dalvik 的開發(fā)者當(dāng)初寫下這幾行代碼的時(shí)候圆仔,心中是這么考慮的:六萬五千多個(gè)方法還不夠你們用的嗎垃瞧?
開發(fā)者在設(shè)計(jì)新功能或者新協(xié)議的時(shí)候,往往顯得過于保守與短視荧缘。比如皆警,IPv4 的設(shè)計(jì)者們顯然并沒有預(yù)料到我們今天會遭遇 IP 地址耗盡的危機(jī)。
現(xiàn)在截粗,同樣的問題出現(xiàn)在了 Android 開發(fā)者的面前信姓。隨著應(yīng)用程序功能的日益復(fù)雜,源碼的規(guī)模正在逐漸增大绸罗,勢必有一天意推,代碼中方法的數(shù)量終將超出限制。最徹底的解決辦法自然是升級 dalvik 的源代碼珊蟀,把計(jì)數(shù)器的計(jì)數(shù)范圍擴(kuò)大菊值。然而外驱,由于當(dāng)前版本的 dalvik 已經(jīng)廣泛運(yùn)行在了大量的安卓設(shè)備中(全世界安卓設(shè)備的激活數(shù)已經(jīng)超過了 10 億臺),這種毫無向前兼容性的解決辦法顯然不可取腻窒。
那么昵宇,作為開發(fā)者,該怎樣避免這個(gè)問題呢儿子?Android 的官方開發(fā)者網(wǎng)站上面有一篇專門討論這個(gè)主題的文章: Building Apps with Over 65K Methods瓦哎。
總結(jié)來說,有兩種可選方案:
一種辦法是減小程序的規(guī)模柔逼,這可以通過刨除無用代碼以及減少項(xiàng)目的依賴來達(dá)成蒋譬。不過這終究只是權(quán)宜之計(jì),只能拖延時(shí)間愉适,并不能阻止末日的到來犯助。
另一種辦法是把編譯生成的字節(jié)碼文件分割成為兩個(gè)或者更多 dex 文件,以此規(guī)避單個(gè) dex 文件中的方法總數(shù)不得超過 65536 的限制维咸。
要知道剂买,dalvik 強(qiáng)制限定了一個(gè) APK 包中只能包含一個(gè)字節(jié)碼文件。 這篇文章提供了一種有趣的思路腰湾,幫助我們理解為什么分割字節(jié)碼文件是可行的雷恃。