移动App性能测评与优化1.5.4 dex文件优化

简介:

1.5.4 dex文件优化

为了达到优化的目的,我们需要先了解dex文件的结构。dex文件结构如表1-2所示。

表1-2 dex文件结构

区 域  描 述  内 容

Header            

索引区  String Id list 指向Data的偏移量  

      Type Id list      

      Method Prototype Id list      

      Field Id list       

      Method Id list         

      Class Definition list        

Data区 ClassData    类数据  常量及变量定义Id

                 接口Id

                 成员函数Prototype Id

                 类Annotation的偏移量

      StringData   字符串数据  类名

                 Proto字符串

                 常量字符串

      Code    函数代码     Dalvik字节码

                 函数Debuginfo的偏移量

                 函数Annotations的偏移量

      StaticValues 静态变量初始值

      Debuginfo   Debug信息 

      Annotation  Annotations

      Map list     

 

简而言之,为了节约空间,dex将原先在各个class文件中重复的信息集中放置在一起,并以索引和指针的形式支持快速访问。虚拟机能够通过索引表在Data区域中找到需要的信息。

下面我们看一个访问字符串的例子。在dex文件结构中,读取字符串需要先到StringIdList中查表,然后根据查到的地址到Data区读取内容。StringIdList的数据结构如下:

struct DexStringId {

  u4 stringDataOff;

};

现在我们模拟虚拟机读取一个字符串,来观察内存的消耗。假设有一个字符串的id = 6728,对应的地址就会是112 + 6728 = 6990。因此虚拟机首先根据string ID读取0x006990 - 0x006994的内容,此时系统会加载0x006000~0x006fff的整页内存,从Pss角度来看,会增加4KB。

虚拟机读到的内容是stringDataOff = 0x531ed4,随后虚拟机会继续从0x531ed4读取字符串内容,假设字符串长度是45字节,则虚拟机会读取0x531ed4~0x531f04的内容,但此时系统也必须加载0x531000~0x531fff的整页内存,从Pss角度来看,会再次增加4KB。

由此可见,在有些情况下,虚拟机读取data区的一个数据,就至少要消耗8KB物理内存。如果多次读取的分散在文件各处的数据,就可能会以4KB的倍数快速消耗内存。

Android SDK提供了dexdump工具来观察dex文件内容,我们以此工具来看看dex的数据内容:

dexdump classes.dex

Processing 'classes.dex'...

Opened 'classes.dex', DEX version '035'

Class #0 header:

...

Class #0            -

  Class descriptor  : 'Laaa/aaa;'

...

Class #1            -

  Class descriptor  : 'Laaa/bbb;'

...

Class #2            -

  Class descriptor  : 'Lbbb/ccc;'

...

根据对dex数据的观察,我们发现dex文件中数据基本是按类名的字母顺序进行排列的,这样同样包名的类会排在一起。但在实际程序执行中,同一个package下的类并不会全部一起调用,而是和很多其他package下的类进行交互,但mmap加载了整个页面,可能会有很多无用数据。为了减少这样的情况,我们在生成文件时要尽量将使用到的数据内容排布在一起。在APK的编译流程中,Proguard混淆工具正好是能够对类名进行修改的,可以根据程序运行的逻辑,将那些会互相调用的类改为同一个package名,这样就可以使它们的数据排布在一起。

以上表数据为例,Class的排列顺序是aaa/aaa、aaa/bbb、bbb/ccc。假设我们的应用运行逻辑是aaa/aaa、bbb/ccc,而aaa/bbb在某些特殊时候才能用到。但在当前的排列情况下,加载了aaa/aaa和bbb/ccc就必然要加载aaa/bbb。我们可以用Proguard等工具来控制类名,将aaa/bbb等不常用的类放在后面,则aaa/bbb平时就不会加载。如下所示:

dexdump classes.dex

Processing 'classes.dex'...

Opened 'classes.dex', DEX version '035'

Class #0 header:

...

Class #0            -

  Class descriptor  : 'La0;' # 原aaa/aaa

...

Class #1            -

  Class descriptor  : 'La1;' # 原bbb/ccc

...

Class #2            -

  Class descriptor  : 'La2;' # ...

...

Class #100            -

  Class descriptor  : 'La100;' # 平时用不到的aaa/bbb

...

经验总结

根据上述的流程,我们探讨了Dalvik Other和.dex mmap部分的内存,大致搞清楚了它们被消耗的机制,以及一些能够减少消耗的方法。经验如下:

在优化内存时,不只有堆内存,还有其他许多类型的内存能够进行分析和优化。

dex文件有很多优化空间。在仔细统计并调整了dex文件的顺序后,往往能够节约1MB以上的mmap内存。

引入SDK库和调用新的系统API时需要考虑成本。有可能一些不常用的功能会导致大量的内存消耗。这时有可能需要多进程方案,将这些影响内存的操作放入临时进程执行。

相关文章
|
19天前
|
存储 Java API
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
76 0
|
2月前
|
JavaScript
uni-app中关于格式化时间的js文件
uni-app中关于格式化时间的js文件
34 0
|
2月前
|
JavaScript Android开发
【问题篇】打包Vue-cli3创建的vue项目成App的apk文件
【问题篇】打包Vue-cli3创建的vue项目成App的apk文件
31 0
|
4月前
|
JSON Dart 安全
Flutter App混淆加固、保护与优化原理
Flutter App混淆加固、保护与优化原理
54 0
|
6月前
mpvue踩坑-未找到入口 app.json 文件,或者文件读取失败,请检查后重新编译
mpvue踩坑-未找到入口 app.json 文件,或者文件读取失败,请检查后重新编译
40 0
|
4月前
|
架构师 Java
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
53 0
|
5月前
|
XML Java Android开发
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
167 0
|
7月前
|
Web App开发 数据安全/隐私保护 iOS开发
app优化ios,iOS app上架流程问题集锦,ASO新手小白必看(上)
app优化ios,iOS app上架流程问题集锦,ASO新手小白必看(上)
|
2月前
|
iOS开发 开发者
【教程】uni-app iOS 打包解决 profile 文件与私钥证书不匹配问题
【教程】uni-app iOS 打包解决 profile 文件与私钥证书不匹配问题
|
2月前
|
开发框架 前端开发 算法
【Qt App 编译 】Qt Cmake 资源文件的加载:如何使用 CMakeLists.txt 文件和资源文件
【Qt App 编译 】Qt Cmake 资源文件的加载:如何使用 CMakeLists.txt 文件和资源文件
40 0