针对dex文件,做android开发的应该都见过,没见过也听说过,至少听说过65536吧,本篇文章就带大家认识以下dex。

什么是dex文件

大家知道JVM 是 JAVA 虚拟机,用来运行 JAVA 字节码程序。Dalvik 是 Google 设计的用于 Android平台的运行时环境,适合移动环境下内存和处理器速度有限的系统。ART 即 Android Runtime,是 Google 为了替换 Dalvik 设计的新 Android 运行时环境,在Android 4.4推出。这块内容可参看我之前的一篇文章《关于Android虚拟机的那些事儿》。

Android 程序一般使用 Java 语言开发,但是 Dalvik 虚拟机并不支持直接执行 JAVA 字节码,而是会对编译生成的 .class 文件进行翻译、重构、解释、压缩等处理,这个处理过程是由 dx 进行处理,处理完成后生成的产物会以 .dex 结尾,称为 Dex 文件。所以说Dex 文件是很多 .class 文件处理后的产物,最终可以在 Android 运行时环境执行。

了解了 Dex 文件以后,对日常开发中遇到一些问题能有更深的理解。如:APK 的瘦身、热修复、插件化、应用加固、Android 逆向工程、64 K 方法数限制。

dex文件有什么好处

有同学可能有疑问了,Android系统其实是基于Java语言上开发(此处暂且不谈kotlin),而Java源码编译后生成的是class字节码文件,该文件也是存储了Java源码的相关信息,Android系统为何不采用使用class文件而使用dex文件呢?

android采用dex代替class文件,且不说与甲骨文的那点小过节,更多的是针对移动设备所做出的努力。class文件中的数据规范分明,每个class代表一个类,结构清晰,但它对于移动设备而言还是有以下弊端:

  • class文件中包含各种数据如常量池、field等,而一个应用中有成百乃至更多的类,使用字节码文件存储类信息,内存占用过大,不适合移动端;
  • class文件是堆栈的加栈模式,加载速度慢;
  • 文件IO操作多,类查找慢;因为每个class文件中只存储了一个Java源文件信息。

这三个是最明显的弊端,因此不适合移动设备的加载使用,而Dex是对众多 .class 文件进行了整合并且做了很多优化,整体统一,空间占用小,易加载(dex基于寄存器),在不脱离java的束缚下是移动端最好的应对方案。

dex文件是怎么生成的

java 代码转化为 dex 文件的流程如图所示:

例如有一个Hello.java文件,则通过两步即可生成dex文件:

第一步: 通过 JDK 的 javac 工具,将 .java文件转化为.class二进制文件。

javac Hello

第二步: 通过 SDK 中的 dx工具,将 .class文件进行翻译、重构、解释、压缩等操作,生成 .dex 文件。

dx --dex --output=Hello.dex Hello.class

dex文件的具体格式

就像 MP3,MP4,JPG,PNG 文件一样,Dex 文件也有它自己的格式,只有遵守了这些格式,才能被 Android 运行时环境正确识别。

Dex 文件整体布局如下图所示:

  • 文件头:header记录了dex文件信息及所有字段大致的分布;
  • 索引区:分别记录了字符串、类型、方法原型、域、方法的索引,这部分指定了dex文件中所有不同类型数据存储的位置,数据最终存储于“数据区”;
  • 数据区:此块可分成普通数据区和链接数据区,后者听起来较为陌生,总所周知Android中常有一些动态链接库so的引用,而链接数据区就是对这个的指向。

dex文件头

文件头区域决定了该怎样来读取这个文件。具体的格式如下表(在文件中排列的顺序就是下面表格中的顺序):

Dex文件头二进制一览:

65536问题

好多同学都知道android可执行文件“.dex”中的Java方法数引用不能超过65536个,否则就会报com.android.dex.DexIndexOverflowException:method IDnotin[0,0xffff]:65536的错误。但是为什么是65536呢?

这个问题是由于dex文件格式限制,一个dex文件中的method个数采用使用原生类型short来索引文件的方法,也就是2个字节共16位,最多表达65536个method,field/class个数也均有此限制,对于dex文件,则是将工程所需要全部class文件合并压缩到一个dex文件期间,也就是Android打包的dex过程中,单个dex文件可被引用的方法总数(自己开发的代码以及所引用的Android框架、类库的代码)被限制为66536。

因此如果工程代码量比较大,方法数若超过65536个则必须采用dex分包形式处理。

对于为什么采用short来作为索引范围,我猜当时工程师考量的问题还是和移动端硬件和内存比较吃紧有关,纯属个人想法。

odex、oat、vdex

dex文件是DVM虚拟机可执行的文件,但是真正在app运行的时候虚拟机并不是执行的dex文件。虚拟机运行程序之前需要对dex文件做进一步优化,进而降低内存占用,提高执行效率。

odex

全称:optimized dex; 即优化过的dex。

Android5.0之前APP在安装时会进行验证和优化,为了校验代码合法性及优化代码执行速度,验证和优化后,会产生odex文件,运行Apk的时候,直接加载odex,避免重复验证和优化,加快了Apk的响应时间。

oat

oat是ART虚拟机运行的文件,是ELF格式二进制文件,包含dex和编译的本地机器指令,oat文件包含dex文件,因此比odex文件占用空间更大。

Android L( 5.0 ) 引入Android Runtime (ART),ART 使用设备自带的 dex2oat 工具来编译应用,提高启动速度,dex2oat默认会把classes.dex翻译成本地机器指令,生成ELF格式的oat文件,ART加载OAT文件后不需要经过处理就可以直接运行,它在编译时就从字节码装换成机器码了,因此运行速度更快。

不过android5.0之后oat文件还是以.odex后缀结尾,但是已经不是android5.0之前的文件格式,而是ELF格式封装的本地机器码。可以认为oat在dex上加了一层壳,可以从oat里提取出dex。

vdex

Android O ( 8.0 ) 引入了vdex,目的是为了降低dex2oat时间。

vdex 文件有助于提升软件更新的性能和用户体验。vdex 文件会存储包含验证程序依赖项且经过预验证的 dex 文件,以便 ART 在应用更新期间无需再次解压和验证 dex 文件。从而优化了启动速度。

vdex 目的不是为了提升性能,而是为了避免不必要的验证Dex 文件合法性的过程,例如首次安装时进行dex2oat时会校验Dex 文件各个section的合法性,这时候使用的compiler filter 为了照顾安装速度等方面,并没有采用全量编译,当app启动运行一段时间后,收集了足够多的jit 热点方法信息,Android会在后台重新进行dex2oat, 将热点方法编译成机器代码,这时候就不用再重复做验证Dex文件的过程了。这点有点类似机器学习。

最后

本文仅仅是对dex整体结构做了一个初步的认识,至于dex内部的深度刨析,作者不做系统开发,因此没有做过深研究。对dex有一个基础看法,这将为以后的类加载、热修复、插件化等技术栈提升有很大的帮助。如果大家有任何的建议或意见,欢迎指出。喜欢的点个赞!

来,同学,坐下,谈谈对Dex文件的认识相关推荐

  1. 逆向开发使用dx.jar、d8.jar、baksmali.jar将jar转dex文件,解决requires --min-sdk-version >= 26 (currently 13)问题

    apk母包中合并第三方SDK代码 当我们需要将某些第三方SDK的代码合并到自己的apk母包的时候,一般的流程是解压第三方SDK的aar文件,然后合并里面的资源文件,assets.res目录直接拷贝合并 ...

  2. 批量提取出apk文件中的classes.dex文件

    应用场景 如果需要批量分析apk以及每个apk文件中的classes.dex 文件.怎么提取出它们?将apk改后缀名变为.zip文件,之后在解压,提取出每个apk文件中的classes.dex文件,这 ...

  3. dex文件结构(三):dex文件差分包分成

    作者:hackest 链接:https://www.jianshu.com/p/5a2e33a61ba2 当程序越来越大之后,出现了一个 dex 包装不下的情况,通过 MultiDex 的方法解决了这 ...

  4. dex文件结构(二):dex文件加载基本原理

    一.Java层调用链 1.1 ActivityThread.performLaunchActivity 一般应用程序的启动都是由点击Launcher上的图标来启动,而点击图标时所执行的操作是start ...

  5. IO操作Dex文件加密,APK加固项目实战

    APK加固原理分析 1.1 APK文件结构 首先让我们先了解一下一个完整的Android应用程序都由哪些文件组成.解压一个apk包,我们可以看到一下的这些文件及文件夹: 每个文件及文件夹的作用如下表所 ...

  6. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )

    文章目录 前言 一.DexPrepare.cpp 中 rewriteDex() 方法分析 二.DvmDex.cpp 中 dvmDexFileOpenPartial() 方法分析 ( 脱壳点 ) 三.D ...

  7. 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )

    文章目录 前言 一.RawDexFile.cpp 中 dvmRawDexFileOpen() 方法分析 前言 上一篇博客 [Android 逆向]整体加固脱壳 ( DexClassLoader 加载 ...

  8. 【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 拷贝 DEX 文件到内置存储 | 加载并执行 DEX 字节码文件 )

    文章目录 一.拷贝 Assets 目录下的 classes.dex 字节码文件到内置存储区 二.加载 DEX 文件并执行其中的方法 三.MainActivity 及执行结果 四.博客资源 一.拷贝 A ...

  9. 【错误记录】记录 Android 命令行执行 Java 程序中出现的错误 ( dx 打包 PC 可执行文件报错 | dalvik 命令执行 kotlin 编译的 dex 文件报错 )

    文章目录 前言 一.Android 命令行与 PC 可执行 JAR 文件不兼容 二.Android 命令行使用 dalvik 命令不能直接执行 Kotlin 编译的 dex 文件 前言 尝试在 And ...

  10. 【Java 虚拟机原理】Dalvik 虚拟机 ( 打包 Jar 文件和 Dex 文件 | 反编译 Dex 文件 | 分析 Dex 文件反编译结果 )

    文章目录 前言 一.打包 Jar 文件和 Dex 文件 1.示例代码 2.打包 Jar 文件 3.打包 Dex 文件 二.反编译 Dex 文件 三.分析 Dex 文件 1.Student 类相关信息 ...

最新文章

  1. elasticsearch 复杂查询小记
  2. 主流路由器固件dd-wrt,tomato,openwrt对比介绍
  3. MySQL统计两部分查询结果记录数量比值
  4. werkzeug LocalProxy
  5. SAP License:CO07利润中心必输
  6. LaTex ——P4 字体字号设置
  7. 实现自己的控制层do-c (仿Struts2和SpringMVC)(六)
  8. 项目介绍star原理_TiDB-Wasm 原理与实现 | Hackathon 优秀项目介绍
  9. EasyUi之书籍功能(CRUD)
  10. OSG读取Tif格式的高程数据
  11. 毕业设计别再做 XX 管理系统了!!!
  12. ”易书网“开发总结——技术篇
  13. Android P cdd(Android 兼容性定义文档)
  14. 怎么用计算机计算化学,计算化学
  15. 小程序之100推荐:801~900
  16. 匿名信一封来信一封云来信表白祝福道歉短信H5公众号系统搭建(搭建赠送人工传话系统+主机管理面板)
  17. 瑞华吉瑞保重大疾病保险怎么样?好不好
  18. 心蓝android版本,心蓝抢票app-心蓝抢票软件预约 _5577安卓网
  19. CSMA/CD协议 详解
  20. java为什么用工厂模式_【Java】为什么建议没事不要随便用工厂模式创建对象?...

热门文章

  1. Excel技能——批量生成excel的工作表名称目录链接
  2. 【Python爬虫系列】Python 爬取上海链家二手房数据
  3. java生成随机数方法
  4. php验证码图片不显示怎么办,php 验证码图片无法显示怎么办
  5. ss导航java宝典_ss导航绅士宝典app下载-ss导航绅士宝典百度网盘官方版下载v1.1.0-七度网...
  6. 如何在html中下载pdf等文件而不是直接打开
  7. linux下安装jemalloc
  8. ACM程序设计大赛简介
  9. html中五号字体是多少像素,5号字是多大(字体尺寸对照表mm)
  10. cdr添加节点快捷键_史上最全CDR快捷键命令汇总