64K问题

65535 方法数问题本质原理

产生 65535 问题的原因

单个 Dex 文件中,method 个数采用使用原生类型 short 来索引,即 2 个字节最多 65536 个 method,field、class 的个数也均有此限制,关于如何解决由于引用过多基础依赖项目,造成 field 超过 65535 问题

对于 Dex 文件,则是将工程所需全部 class 文件合并且压缩到一个 DEX 文件期间,也就是使用 Dex 工具将 class 文件转化为 Dex 文件的过程中, 单个 Dex 文件可被引用的方法总数(自己开发的代码以及所引用的 Android 框架、类库的代码)被限制为 65536。

这就是 65535 问题的根本来源。

LinearAlloc 问题的原因

这个问题多发生在 2.x 版本的设备上,安装时会提示 INSTALL_FAILED_DEXOPT,这个问题发生在安装期间,在使用 Dalvik 虚拟机的设备上安装 APK 时,会通过 DexOpt 工具将 Dex 文件优化为 ODex 文件,即 Optimised Dex,这样可以提高执行效率。

在 Android 版本不同分别经历了 4M/5M/8M/16M 限制,4.2.x 系统上可能都已到 16M,在 Gingerbread 或以下系统 LinearAllocHdr 分配空间只有 5M 大小的, 高于 Gingerbread 的系统提升到了 8M。Dalvik linearAlloc 是一个固定大小的缓冲区。dexopt 使用 LinearAlloc 来存储应用的方法信息。Android 2.2 和 2.3 的缓冲区只有 5MB,Android 4.x 提高到了 8MB 或 16MB。当应用的方法信息过多导致超出缓冲区大小时,会造成 dexopt 崩溃,造成 INSTALL_FAILED_DEXOPT 错误。

本质

65535 = 2^16-1,也称之为 64K 方法数问题。指的是 Android Dalvik 可执行文件.dex 中的 Java 方法数引用超过 65535。
Android Apk 本质是一个压缩文件,里面包含的 classes.dex 文件是可执行的 Dalvik 字节码文件,存放的是所有编译后的 Java 代码;Dalvik 可执行文件规范限制了单个.dex 文件最多能引用的方法数是 65536 个(最初设计是错误的),这其中包含了 Android Framework、APP 引用的第三方库及 APP 自身的方法数。

表现

表现在构建 App 时的编译错误,导致构建失败。

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
The number of method references in a .dex file cannot exceed 64K

解决

Android5.0(API21) 之前

Android5.0(API21) 之前系统使用的是 Dalvik 虚拟机,默认情况下 Dalvik 为每个 apk 只生成一个 classes.dex 文件。解决方法是,拆分成多个 classesxxx.dex,先加载主 classes.dex,然后加载从.dex。或者用 google 提供的MultiDex support 库。

Android5.0+

Android5.0+ 使用的是 ART 虚拟机替代了 Dalvik 虚拟机,ART 支持从 apk 中加载多个.dex 文件,在应用安装期间,它会执行一个预编译操作,扫描 apk 中的 xxx.dex 文件并将它们编译成一个单一的 .oat 文件,在应用运行时去加载这个.oat 文件,而不是一个一个的加载.dex 文件。

MultiDex 局限

Reference

https://developer.android.com/intl/zh-cn/tools/building/multidex.html

关于『65535 问题』的一点研究与思考
http://blog.csdn.net/zhaokaiqiang1992/article/details/50412975