Android工程中方法数超过65536解决方法
1 Dalvik虚拟机(DVM)和Java虚拟机(JVM)
JVM是Java Virtual Machine,DVM是Dalvik Virtual Machine,是Android中使用的虚拟机,每个进程对应着一个Dalvik虚拟机实例。JVM是基于虚拟栈的虚拟机,而DVM是基于寄存器的虚拟机。寄存器存取速度比栈快的多,DVM可以根据硬件实现最大的优化,比较适合移动设备。
virtual [ˈvɜːrtʃuəl] 虚拟的 machine [məˈʃiːn] 机器
JVM运行的是Java字节码(.class)文件,DVM运行的是Dalvik字节码(.dex)文件。Android程序编译完之后生成的是.class文件,然后Dex工具会把.class文件处理成.dex文 件,然后再把资源文件和.dex文件等打包成apk文件。.class文件存在很多的冗余信息,Dex工具会去除掉这些冗余信息,并把所有的.class文件整合到.dex可执行(Dalvik Executable)文件中。
executable [ˌeksɪˈkjuːtəbl] 可执行的;可实行的
很长时间以来,Dalvik虚拟机一直被用户指责为拖慢安卓系统运行速度不如IOS的根源。Android 5.0 改动幅度较大,谷歌直接删除Dalvik,用ART替代它。
2 “64k引用限制”
Java字节码(.class)文件中,局部变量会被放入局部变量表中,继而被压入堆栈供操作码进行运算。Dalvik字节码文件(.dex)中,局部变量会被赋给65536个可用的寄存器中的任何一个,Dalvik指令直接操作这些寄存器,而不是访问堆栈中的元素。
当方法数超过65536的时候,会报如下的错误:
The number of method references in a .dex file cannot exceed 64K.
Caused by: com.android.tools.r8.utils.AbortException: Error: Cannot fit requested classes in a single dex file (# methods: 68815 > 65536)
65536代表了引用的总数上限,单个.dex文件(Dalvik可执行文件)中最多可以包含65536个方法,其中包括Android Framework方法、第三方引用库方法、和APP自身方法总数。因为65536 = 64 × 1024,这一限制被称为“64k引用限制” 。 这个极限就要求我们配置应用程序的构建过程,需要生成多个Dex文件, 所以称为multidex配置。
multi [ˈmʌlti] 多
Android 5.0 (API leve 21)之前的系统使用Dalvik虚拟机。默认情况下,Dalvik限制一个APK只有一个.dex文件 ,为了绕过这个限制,需要使用Android官方提供的com.android.support:multidex库来解决这个问题。
Android 5.0(API leve 21)和更高的系统使用的runtime是ART ,支持APK文件加载多个.dex文件。ART在安装应用时,会执行一个预编译操作,扫描多个classes(..N).dex文件编译成一个.oat的文件。
以下是将apk解压缩后的内容:

尽量避免“64k引用”限制:
- 选择三方依赖库的时候做好调研工作,选择满足自己功能的并且尽量小的(建议能用源码的用源码,对于以后自己的定制和维护很有好处);
- 正式打包构建的时候,使用代码混淆器
ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到APK中;
3 解决“64k引用限制”
第一步:添加配置和依赖(mudule下build.gradle文件)
配置:
defaultConfig {
multiDexEnabled true
}
依赖:
implementation 'com.android.support:multidex:1.0.3'
第二步:继承android.support.multidex.MultiDexApplication类
分两种情况,第一种有自己的Application,重写Application中这个方法如下:
public class WanAdroidApplication extends Application {
@Override
protected void attachBaseContext(Contextbase) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
第二种没有自己的Application,如果我们的APP没有重写过Application类,就直接继承MultiDexApplication,然后在manifest.xml中注册Application即可。
以下是MultiDexApplication的源码:
public class MultiDexApplication extends Application {
public MultiDexApplication() {
}
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
与此同时可能会报java.lang.OutOfMemoryError: Java heap space错误,那么解决方法是:在mudule的build.gradle中android中添加如下代码:
dexOptions { // 加大java堆内存大小
javaMaxHeapSize "2g" // 这里2g或者4g都可以
}
4 multidex库的一些限制因素
4.1 第二个Dex文件过大问题
.dex文件安装到设备的过程非常复杂,如果第二个.dex文件太大,可能导致应用无响应,此时应该使用ProGuard减小.dex文件的大小。
4.2 系统低版本问题
- 由于
Dalvik linearAlloc的Bug,应用应该无法在Android 4.0之前的版本启动 ,如果你的应用要支持这些版本就要多执行测试。 - 同样因为
Dalvik linearAlloc的限制,如果请求大量内存可能导致崩溃。Dalvik linearAlloc是一个固定大小的缓冲区。在应用的安装过程中,系统会运行一个名为dexopt的程序为该应用在当前机型中运行做准备。dexopt使用LinearAlloc来存储应用的方法信息。Android 2.2和2.3的缓冲区只有5MB,Android 4.x提高到了8MB或16MB。当方法数量过多导致超出缓冲区大小时,会造成dexopt崩溃。 Multidex构建工具还 支持指定哪些类必须包含在首个.dex文件中,因此可能会导致某些类库(例如某个类库需要从原生代码访问Java代码)无法使用。
alloc 分配(allocate, allocation)
总之就是在做低版本兼容的时候可能会崩溃,要多测试。(不过现在基本面向的用户使用的都是4.4以上的系统,这些情况出现的几率大大降低)。
参考
https://blog.csdn.net/gongxiaoou/article/details/81281415
https://blog.csdn.net/songshoubin/article/details/106130833
749

被折叠的 条评论
为什么被折叠?



