Android出现65535的原因

xiaoxiao2021-02-28  51

       众所周知当Android app代码足够多时, 编译会报方法数超过65535问题。 Google为了解决这个问题,提供了multi-dex方案, 即将代码编译成若干个dex文件,如classes.dex, classes2.dex...classes*.dex。 

      我们关心的是怎么解决这个问题,包括插件化、multi-dex等等方案,  网上相关的博客非常多。

      但是有人想过Android为什么要报这个问题, 在哪里报的?

      dalvik或art虚拟机在加载*.dex文件时会生成一个DexFile实例, 该实例包含dex文件的各种属性。

      

         DexFile结构体的第一个属性pOptHeader指针的数据类型是DexHeader, 看看DexHeader的定义:

/* * Direct-mapped "header_item" struct. */ struct DexHeader { u1 magic[8]; /* includes version number */ u4 checksum; /* adler32 checksum */ u1 signature[kSHA1DigestLen]; /* SHA-1 hash */ u4 fileSize; /* length of entire file */ u4 headerSize; /* offset to start of next section */ u4 endianTag; u4 linkSize; u4 linkOff; u4 mapOff; u4 stringIdsSize; u4 stringIdsOff; u4 typeIdsSize; u4 typeIdsOff; u4 protoIdsSize; u4 protoIdsOff; u4 fieldIdsSize; u4 fieldIdsOff; u4 methodIdsSize; u4 methodIdsOff; u4 classDefsSize; u4 classDefsOff; u4 dataSize; u4 dataOff; };

           从DexHeader的定义可以看出, Android对方法总数和属性总数都限制为4个字节即65535。大概是下午犯困惯性思维写错了, 无符号整型4个字节取值范围为0~2^32-1。

         方法、属性、类信息等等都有对象的offset, 为什么呢?

推断:

        一个dalvik或者art虚拟机可以加载若干个dex文件, 在framework层限制了单个dex的最大方法数量、最大属性数量等等(详见DexFormat.java)。 感觉methodIdsSize数据类型应该是u2, 不明白为什么是u4。。。

       offset是位置偏移,用于获取对应属性的头指针。 而每个属性对应连续的内存空间且单个实例(例如一个方法)占用空间大小相等, 虚拟机做个循环加载各个属性。 详见DexFile.cpp的dexFileSetupBasicPointer函数, 即每个属性分配头指针。

        PS:我们写代码时一般是方法数量比属性数量多, 所有一般提示方法总数超过65535; 其实属性总量超过65535个时,也会报同样的问题!

         从Native层DexFile结构体定义可以看出, 每个dex文件的方法数和属性数必须都小于65535,  否则会越界(因为只有4个字节)。

        那么编译时的错误是哪里提示的呢? 经过搜索代码, 发现是在MemberIdsSection.java提示的。

         DexFormat.MAX_MEMBER_IDX等于65535, 所以编译时会报错。 

总结: 

1、framework层限制了单个dex文件的最大方法数量、最大属性数量等等为65535(占2个字节),但native层DexHeader中对应字段定义为4个字节, 暂时没找出原因。。。 

2、DexHeader各属性对应的offset是偏移, 用于获取真正的头指针。  例如dex文件含有10000个方法, methodIdsSize等于10000,通过methodIdsOff拿到头指针, 就可以读取这10000个方法各自的属性。

      

转载请注明原文地址: https://www.6miu.com/read-77487.html

最新回复(0)