这个周末打算开个新系列,总结下热修复与插件化相关知识点,framework做久了,app也不能丢。
开篇文章先打个基础,针对class文件以及dex文件做个简单对比。
一、什么是class 、dex
class: jvm识别、加载并执行的文件格式。
dex: 能被dvm、art识别、加载并执行的文件格式。
二、如何生成并执行class 、dex
class的生成与执行:
jdk命令
编译生成Hello.class文件 javac Hello.java
执行Hello.class文件 java Hello
dex的生成与执行:
android sdk命令
先通过javac生成.class文件
然后生成dex文件 dex -dex -output hello.dex(生成文件) hello.class(源文件)
文件push到手机 adb push hello.dex /storage/emulated/0
执行adb shell dalvikvm -cp /sdcard/hello.dex hello(执行哪个class)
三、class、dex文件结构解析
class文件:
8位字节的二进制流文件,各个数据紧密排列无间隙,每个类或接口都是单独的class。
字段表:
类型 | 描述 | 备注 |
---|---|---|
u4 | magic | 魔数:0xCAFEBABE |
u2 | minor_version | 小版本号 |
u2 | major_version | 主版本号 |
u2 | constant_pool_count | 常量池大小,从1开始 |
cp_info | constant_pool[constant_pool_count - 1] | 常量池信息 |
u2 | access_flags | 访问标志 |
u2 | this_class | 类索引 |
u2 | super_class | 父类索引 |
u2 | interfaces_count | 接口个数 |
u2 | interfaces[interfaces_count] | 接口类索引信息 |
u2 | fields_count | 字段数 |
field_info | fields[fields_count] | 字段表信息 |
u2 | methods_count | 方法数 |
method_info | methods[methods_count] | 方法表信息 |
u2 | attributes_count | 属性个数 |
attribute_info | attributes[attributes_count] | 属性表信息 |
数据项的不同长度分别用u1, u2, u4, u8表示, 分别表示一种数据项在class文件中占据一个字节, 两个字节, 4个字节和8个字节。
010 Editor 工具 查看class文件
class文件弊端:内存占用大;堆栈的加栈模式,加载速度慢;文件io操作多,类加载查找慢等。因此不适合移动端。
dex文件:
8位字节的二进制流文件,各个数据紧密排列无间隙,整个应用的所有java源文件都放在一个dex中。
链接数据区 动态库
数据名称 | 解释 |
---|---|
header | dex文件头部,记录整个dex文件的相关属性 |
string_ids | 字符串数据索引,记录了每个字符串在数据区的偏移量 |
type_ids | 类似数据索引,记录了每个类型的字符串索引 |
proto_ids | 原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表 |
field_ids | 字段数据索引,记录了所属类,类型以及方法名 |
method_ids | 类方法索引,记录方法所属类名,方法声明以及方法名等信息 |
class_defs | 类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量 |
data | 数据区,保存了各个类的真是数据 |
link_data | 连接数据区 |
其中head记录了dex文件的一些基本信息,以及大致的数据分布:
字段名称 | 偏移值 | 长度 | 说明 |
---|---|---|---|
magic | 0x0 | 8 | 魔数字段,值为"dex\n035\0" |
checksum | 0x8 | 4 | 校验码 |
signature | 0xc | 20 | sha-1签名 |
file_size | 0x20 | 4 | dex文件总长度 |
header_size | 0x24 | 4 | 文件头长度,009版本=0x5c,035版本=0x70 |
endian_tag | 0x28 | 4 | 标示字节顺序的常量 |
link_size | 0x2c | 4 | 链接段的大小,如果为0就是静态链接 |
link_off | 0x30 | 4 | 链接段的开始位置 |
map_off | 0x34 | 4 | map数据基址 |
string_ids_size | 0x38 | 4 | 字符串列表中字符串个数 |
string_ids_off | 0x3c | 4 | 字符串列表基址 |
type_ids_size | 0x40 | 4 | 类列表里的类型个数 |
type_ids_off | 0x44 | 4 | 类列表基址 |
proto_ids_size | 0x48 | 4 | 原型列表里面的原型个数 |
proto_ids_off | 0x4c | 4 | 原型列表基址 |
field_ids_size | 0x50 | 4 | 字段个数 |
field_ids_off | 0x54 | 4 | 字段列表基址 |
method_ids_size | 0x58 | 4 | 方法个数 |
method_ids_off | 0x5c | 4 | 方法列表基址 |
class_defs_size | 0x60 | 4 | 类定义标中类的个数 |
class_defs_off | 0x64 | 4 | 类定义列表基址 |
data_size | 0x68 | 4 | 数据段的大小,必须4k对齐 |
data_off | 0x6c | 4 | 数据段基址 |
010 Editor 工具 查看dex文件
dex:区域复用。data数据区对应value。
class 与dex对比:
本质都是虚拟机执行文件,dex从class演变的,以适应移动端。
class存在区域冗余(一个class一个常量池),dex去除冗余并整合,极大减少执行文件体积。