作者HuangJC (吹笛牧童)
看板java
标题multidex 讨论
时间Thu Jun 23 12:44:34 2016
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://webptt.com/cn.aspx?n=bbs/java/M.1466657081.A.8C2.html
※ 编辑: HuangJC (60.251.197.55), 06/23/2016 12:47:53
1F:推 LPH66: 64K 是 dex 的指令集设计上的问题 06/23 13:45
2F:→ LPH66: 其实 java 的 bytecode 本来也是有这限制的 06/23 13:46
3F:→ LPH66: invokevirtual 後面跟的数字也是最大 64K 06/23 13:46
4F:→ LPH66: 但 java class 的函数计数只限於单一 class 06/23 13:47
5F:→ LPH66: 所以除非是超巨型 class 不然应该不会碰到 06/23 13:47
这合理多了, 毕竟 class 里 function 很多,但对内很多,对外则隐藏细节
宣告为 private 的外部根本没必要见到 (我都有尽量封起来)
既然写 class 的精神就是尽量隐藏细节,就不应该全部 class 编一份表格
这样这份表格等於曝露了所有 api 接口,根本就没有 private 的感觉
全都 public 了...
所以说是 java 的限制,这不知是我看错还是那几份文件写错
6F:→ LPH66: 但 dex 是把所有 class 打包成一个超大包 dex 06/23 13:47
那我就不知它有什麽问题非得这麽做了
它大可改回来,而不是叫我们学 multidex
7F:→ LPH66: 因此所有 class 的内容全部加在一起才会撞到限制 06/23 13:48
8F:→ LPH66: 至於 function name 的问题, 不论是 bytecode 或 dex 06/23 13:48
9F:→ LPH66: 都是有一个「method 列表」, 用你提到的字串表示 method 06/23 13:49
10F:→ LPH66: 实际的 bytecode / dex assembly 上还是使用列表索引 06/23 13:50
11F:→ LPH66: class bytecode 其实某个意味上还更惊悚: 它只有一个常数池 06/23 13:51
12F:→ LPH66: 所有物件/函数/成员变数等等的参考都在常数池里有位置 06/23 13:51
13F:→ LPH66: 不像 dex 是物件一个池, 方法一个池, 字串一个池等等 06/23 13:52
14F:→ LPH66: 这当然也跟 class 一般大小并不大有关就是 06/23 13:52
15F:→ ssccg: 其实multidex就是改成很多个class file的方向啊 06/23 18:08
16F:→ ssccg: 後续的问题是旧版Android没有原生支援读取多个dex造成的 06/23 18:10
17F:→ HuangJC: 所以新版完全无痛解决了吗?毕竟公司现在只有我有4.3 06/23 18:21
18F:→ HuangJC: 如果说维护成本太高,5.0以上市占又高,我们可能直接舍弃 06/23 18:21
19F:→ HuangJC: 那些维护的 code;交给 compiler 就好了.. 06/23 18:21
20F:→ ssccg: 5.0以後其实是换了一套VM(ART),会在安装时先把所有dex再 06/23 18:26
21F:→ ssccg: compile成另一格式的执行档oat,VM和档案格式都换了自然可 06/23 18:28
22F:→ 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
23F:→ ssccg: AS可以写Java,新增module选Java Library,然後在Run > 06/23 18:42
24F:→ ssccg: Edit Configurations自己新增一个Application类型的 06/23 18:43
25F:→ ssccg: 设好Main class就能跑了,console就是Run那个视窗 06/23 18:44
26F:→ ssccg: bytecode java最简单就用JDK的javap 06/23 18:50
27F:→ ssccg: dex用android SDK的dx --dump或dexdump 06/23 18:52
28F:推 swallowcc: mac可以装多重版本jdk, 然後用command line切换版本 06/23 22:59