隨着項目的功能增多,產品框架也會越來越大,要實現的邏輯也會更多,遇到method個數超出65536個這個問題幾乎是每一個Android碼農必有的經歷,我們一直忙於解決問題,可能這個問題百度一下即可解決,卻沒有真正去探知究竟。最近我學習熱修復的過程中,再次遇到這個問題,特分析一下爲什麼會出現method個數超出65536個而導致編譯失敗問題,以作記錄。
由於無論android-19出現的art,還是之前的dalvik,對Dex文件的定義中,都將方法大小的定義uint32_t類型(uint32_t包含8個字節),直接決定了每個Dex文件的方法數不能超過65536個。
dalvik虛擬機對Dex文件的定義(部分):
libdex/DexFile.h(dalvik):
/*
* 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; /* methodIdsSize是u4類型,而u4從uint32_t聲明定義的,8個字節的限制導致了此錯誤*/
u4 methodIdsOff;
u4 classDefsSize;
u4 classDefsOff;
u4 dataSize;
u4 dataOff;
};
vm/Common.h
/*
* These match the definitions in the VM specification.
*/
typedef uint8_t u1;
typedef uint16_t u2;
typedef uint32_t u4;
typedef uint64_t u8;
typedef int8_t s1;
typedef int16_t s2;
typedef int32_t s4;
typedef int64_t s8;
art虛擬機對dex文件的定義(部分)
runtime/dex_file.h(art):
// Raw header_item.
struct Header {
uint8_t magic_[8];
uint32_t checksum_; // See also location_checksum_
uint8_t signature_[kSha1DigestSize];
uint32_t file_size_; // size of entire file
uint32_t header_size_; // offset to start of next section
uint32_t endian_tag_;
uint32_t link_size_; // unused
uint32_t link_off_; // unused
uint32_t map_off_; // unused
uint32_t string_ids_size_; // number of StringIds
uint32_t string_ids_off_; // file offset of StringIds array
uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535
uint32_t type_ids_off_; // file offset of TypeIds array
uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535
uint32_t proto_ids_off_; // file offset of ProtoIds array
uint32_t field_ids_size_; // number of FieldIds
uint32_t field_ids_off_; // file offset of FieldIds array
uint32_t method_ids_size_; // number of MethodIds
uint32_t method_ids_off_; // file offset of MethodIds array
uint32_t class_defs_size_; // number of ClassDefs
uint32_t class_defs_off_; // file offset of ClassDef array
uint32_t data_size_; // unused
uint32_t data_off_; // unused
// Decode the dex magic version
uint32_t GetVersion() const;
private:
DISALLOW_COPY_AND_ASSIGN(Header);
};