看板 java 關於我們 聯絡資訊
http://www.cnblogs.com/yydcdut/p/4887157.html 這篇看過,雖然通篇中文,不過處處難懂 Orz 1.為什麼 method count 不得多於 64K? 從前 x86 時代,我是有學機械語言及組合語言的 所以對於一個 function 不能大於多少 size 可以理解 原因就是一個 jmp 或 call 指令,其後只帶幾個 byte (如果只帶一個,限制就在 256 byte, 帶兩個,限制就在 65536 byte) 而 x86架構下有所謂"段暫存器"(哇塞,考古到這超懷念) 因此如果只用兩個 byte 來表達位址,那就是段內跳躍 只用一個 byte,常見的不是絕對定址 (取出目前這道指令的位址,把它 16位元的 hibyte 留著, lobyte 改以 jmp 後帶的一個 byte 取代) 而是相對定址 (取出目前指令位址,加上 jmp 後帶的一個 byte, 而且這個 byte 是當成 signed,有正負號的,因此可以往前後跳 127 byte) 更大的則是帶四個 byte, 那就可以做32位元跳躍 至於以前雖然有 32 位元位址觀念,但其實只有 20條位址線 這種偷吃步引起的奇怪限制,討論就更多了 我們其實都是跟著 compiler 給的架構一起成長 XDDDD 本來想詳述這段,但一來離題,二來無法講得乾淨 跳回 android dex 繼續談: 我明明看 java 編出來的 code 裡面有一堆 function name (因此亂恐怖的,如果不攪拌一下,根本可以從執行檔反組譯出程式來) 所以我認為它的 function call 實現方式,應該就是直接去 mapping function name 吧! 字串能有多少變化,funtion 就能有多少,不是嗎? java 又沒把指令 compile 完後,變成只是個數字 fun1 fun2 fun3 . . . fun65536 像上面那樣,如果真的指令只能用數字 access,那我就理解它指令數只能有 64K 個 可是比如 reflect function,都是用 function name 把函式指標取出來 看來即使編譯成了執行檔,function name 也沒被丟掉 這種定址法其實很像 win 之下的 DLL, 可以用 GetProcAddress https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx 它傳入的參數可是字串,是 function name 那怎麼會有 64K 限制? 或許 Java 是允許用 function name 定址 但無論如何它內部就是非得用 function number 來呼叫 (可能是這樣可以寫 table, 不用一直做字串比對,速度會比較快?) 好吧,那就先接受這個限制(反正我又寫不出 compiler,我不接受也不行) 但切 multidex 我又會有另一個問題 2.若我用 DLL 來理解 dex 的話 那不只是要把太大的程式切成兩個 dex 而且,兩個 dex 間,還不得互相呼叫 比如,若我的程式已經有 65538 個函式(就是只多兩個) 那並不是切成相等的兩塊,每塊 32769 個函式就好 而是,第一個 dex 的函式,都不能去呼叫第二個 dex 的函式 因為有定址空間誤會的問題 如果切出一個 main-dex 然後由它載入 dex1 (function 相加總數不能超過 64K) 等要使用 dex2 時,dex1 還得退出 (這時 main-dec 加 dex2 function 總數還是不能超過 64K) 那我就懂了 (喔,那就和 win 下寫 dll 的問題一樣了) -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.251.197.55 ※ 文章網址: https://www.ptt.cc/bbs/java/M.1466657081.A.8C2.html ※ 編輯: HuangJC (60.251.197.55), 06/23/2016 12:47:53
LPH66: 64K 是 dex 的指令集設計上的問題 06/23 13:45
LPH66: 其實 java 的 bytecode 本來也是有這限制的 06/23 13:46
LPH66: invokevirtual 後面跟的數字也是最大 64K 06/23 13:46
LPH66: 但 java class 的函數計數只限於單一 class 06/23 13:47
LPH66: 所以除非是超巨型 class 不然應該不會碰到 06/23 13:47
這合理多了, 畢竟 class 裡 function 很多,但對內很多,對外則隱藏細節 宣告為 private 的外部根本沒必要見到 (我都有盡量封起來) 既然寫 class 的精神就是儘量隱藏細節,就不應該全部 class 編一份表格 這樣這份表格等於曝露了所有 api 接口,根本就沒有 private 的感覺 全都 public 了... 所以說是 java 的限制,這不知是我看錯還是那幾份文件寫錯
LPH66: 但 dex 是把所有 class 打包成一個超大包 dex 06/23 13:47
那我就不知它有什麼問題非得這麼做了 它大可改回來,而不是叫我們學 multidex
LPH66: 因此所有 class 的內容全部加在一起才會撞到限制 06/23 13:48
LPH66: 至於 function name 的問題, 不論是 bytecode 或 dex 06/23 13:48
LPH66: 都是有一個「method 列表」, 用你提到的字串表示 method 06/23 13:49
LPH66: 實際的 bytecode / dex assembly 上還是使用列表索引 06/23 13:50
LPH66: class bytecode 其實某個意味上還更驚悚: 它只有一個常數池 06/23 13:51
LPH66: 所有物件/函數/成員變數等等的參考都在常數池裡有位置 06/23 13:51
LPH66: 不像 dex 是物件一個池, 方法一個池, 字串一個池等等 06/23 13:52
LPH66: 這當然也跟 class 一般大小並不大有關就是 06/23 13:52
ssccg: 其實multidex就是改成很多個class file的方向啊 06/23 18:08
ssccg: 後續的問題是舊版Android沒有原生支援讀取多個dex造成的 06/23 18:10
HuangJC: 所以新版完全無痛解決了嗎?畢竟公司現在只有我有4.3 06/23 18:21
HuangJC: 如果說維護成本太高,5.0以上市佔又高,我們可能直接捨棄 06/23 18:21
HuangJC: 那些維護的 code;交給 compiler 就好了.. 06/23 18:21
ssccg: 5.0以後其實是換了一套VM(ART),會在安裝時先把所有dex再 06/23 18:26
ssccg: compile成另一格式的執行檔oat,VM和檔案格式都換了自然可 06/23 18:28
ssccg: 以修掉當初設計Dalvik指令集的錯誤了.. 06/23 18:29
剛打的,刪掉一大段 想寫個小程式驗,卻寫好久 順便問兩個問題: 1.AS 可以寫純 Java 程式嗎? (其實我想要這個,因為我要實驗 Java 語法,沒必要 upload 至手機,那太慢) 看來不行 2.Eclipse 可以,但我不想裝 Java 1.6 (我是用 Mac),請問怎麼做? 我有裝最新的 Java 1.8 了.. 同事叫我只留一套,因為自從 Build Machine build 的才會 endless loop 後 他說大家要統一 (要死一起死的意思,才能對質 XD;但我的 build 不會 endless loop 耶) 嗯,還是前面問的:那我要怎麼看 bytecode? 看來要對質,還是要對到這境界才行.. ※ 編輯: HuangJC (60.251.197.55), 06/23/2016 18:36:45
ssccg: AS可以寫Java,新增module選Java Library,然後在Run > 06/23 18:42
ssccg: Edit Configurations自己新增一個Application類型的 06/23 18:43
ssccg: 設好Main class就能跑了,console就是Run那個視窗 06/23 18:44
ssccg: bytecode java最簡單就用JDK的javap 06/23 18:50
ssccg: dex用android SDK的dx --dump或dexdump 06/23 18:52
swallowcc: mac可以裝多重版本jdk, 然後用command line切換版本 06/23 22:59