Redex安卓Apk优化技术研究

Redex介绍

ReDex 是 Facebook 开源的工具,通过对字节码进行优化,以减小 Android Apk 大小,同时提高 App 启动速度。
GitHub:ReDex github,官网主页:fbredex.com

本次研究完成了Redex在Ubuntu linux上的安装和配置,进行了Redex优化测试, 实验了Redex优化的主要流程, 包括Inderdex。

Redex优化的基础知识

可以先看看这几篇文章:

Ubuntu上安装Redex

Redex目前支持Ubuntu Linux和Mac系统, 安装时需要编译源码,Ubuntu下面需要有sudo权限才能安装。
安装过程参考官方文档。

Ubuntu 14.04 LTS (64-bit)

sudo apt-get install \
    g++ \
    automake \
    autoconf \
    autoconf-archive \
    libtool \
    libboost-all-dev \
    liblz4-dev \
    liblzma-dev \
    make \
    zlib1g-dev \
    binutils-dev \
    libjemalloc-dev \
    libiberty-dev \
    libjsoncpp-dev

Download, Build and Install

Get ReDex from GitHub:

git clone https://github.com/facebook/redex.git
cd redex

Now, build ReDex using autoconf and make.

autoreconf -ivf && ./configure && make
sudo make install

然后就可以在命令行下运行Redex了

Redex Indexdex介绍

Interdex优化比较复杂,默认配置是不开启的,具体看Interdex文档
Interdex Pass 可以优化dex中class的顺序,以及class在不同的dex中的分布(如果是app使用了multidex)
按照class在实际运行中调用的顺序在dex中进行重新排序,可以带来几个好处:

  • 更少的IO
  • 更少的内存占用
  • 更少page cache污染

Redex默认的配置文件是不包含Inderdex这一步的。增加Inderdex后的配置文件如下:

{
  "redex" : {
    "passes" : [
      "ReBindRefsPass",
      "BridgePass",
      "SynthPass",
      "FinalInlinePass",
      "DelSuperPass",
      "SingleImplPass",
      "SimpleInlinePass",
      "StaticReloPass",
      "RemoveEmptyClassesPass",
      "ShortenSrcStringsPass",
      "InterDexPass"
    ],
   "coldstart_classes":"app_list_of_classes.txt" //class调用顺序列表
  }
}

生成输入数据

如何得到实际运行中class的调用顺序?

首先需要收集app的运行数据

按照典型使用场景操作app,获取heap dump文件, 使用redex提供的脚本redex/tools/hprof/dump_classes_from_hprof.py分析dump文件,得到class列表。
这里有个坑,首先是dump_classes_from_hprof.py在python2运行都有错误, Python2需要安装enum34后才能正常运行, 不兼容python3
在ubuntu上安装enum34后,用python2.7运行,可以得到class列表

具体操作过程如下

// get the process if of your app

adb shell ps | grep YOUR_APP_NAME | awk '{print $2}' > YOUR_PID ( if you don't have awk, the second value is the pid of your app)

// dump the heap of your app. You WILL NEED ROOT for this step

adb root
adb shell am dumpheap YOUR_PID /data/local/tmp/SOMEDUMP.hprof

// copy the heap to your host computer

adb pull /data/local/tmp/SOMEDUMP.hprof YOUR_DIR_HERE/.

// pass the heap dump to the python script for parsing and printing out the class list
// Note that the script needs python 2

YOUR_PYTHON_2_PATH redex/tools/hprof/dump_classes_from_hprof.py --hprof YOUR_DIR_HERE/SOMEDUMP.hprof > list_of_classes.txt

测量优化效果

主要是看app内存占用和 .dex mmap

adb shell ps | grep com.test.app | awk '{ print $2 }'
9003

[R:\AndroidM\packages\apps]$ adb shell dumpsys meminfo 9003
Applications Memory Usage (kB):
Uptime: 2329984 Realtime: 2329984

** MEMINFO in pid 9003 [com.test.app] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap    10711    10044        0        0    44416    40455     3960
  Dalvik Heap     2201     2172        0        0    35719    33937     1782
 Dalvik Other     5424     4984        0        0                           
        Stack      516      516        0        0                           
       Ashmem        4        0        0        0                           
    Other dev        5        0        4        0                           
     .so mmap      967      152      148      360                           
    .apk mmap      271        0       56        0                           
    .ttf mmap        8        0        0        0                           
    .dex mmap     4531        8     4464        0                           
    .oat mmap     2274        0      776        0                           
    .art mmap     2761     1352     1020        0                           
   Other mmap       94        8        8        0                           
    GL mtrack     4196     4196        0        0                           
      Unknown      190      188        0        0                           
        TOTAL    34153    23620     6476      360    80135    74392     5742

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     4544
         Native Heap:    10044
                Code:     5604
               Stack:      516
            Graphics:     4196
       Private Other:     5192
              System:     4057

               TOTAL:    34153      TOTAL SWAP (KB):      360

 Objects
               Views:       48         ViewRootImpl:        0
         AppContexts:        2           Activities:        1
              Assets:        3        AssetManagers:        2
       Local Binders:       12        Proxy Binders:       27
       Parcel memory:       13         Parcel count:       52
    Death Recipients:        0      OpenSSL Sockets:        0

 SQL
         MEMORY_USED:      663
  PAGECACHE_OVERFLOW:       88          MALLOC_SIZE:       62

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       68            512      225/36/22  /data/user/0/com.test.app/databases/MyTicket

App冷启动时间测试

我们常说的App冷启动,是指启动时你的应用程序的进程是没有创建的. 这也是大部分应用的使用场景.用户在桌面上点击你应用的 icon 之后,首先要创建进程,然后才启动 MainActivity.
这时候adb shell am start -W packagename/MainActivity 返回的结果,就是标准的应用程序的启动时间(注意 Android 5.0 之前的手机是没有 WaitTime 这个值的)
具体可以参考怎么计算apk的启动时间?
如果只关心某个应用自身启动耗时,参考TotalTime;如果关心系统启动应用耗时,参考WaitTime;如果关心应用有界面Activity启动耗时,参考ThisTime。

我编写了一个python脚本,可以自动进行多次冷启动,并画出启动时间统计图,计算平均启动时间。用这个脚本可以很方便的测量任意app的启动时间。
打开app,马上运行adb shell dumpsys activity top,可以看到app的包名和启动Activity, 测试脚本需要输入包名和启动activity的完整类名。

Redex优化效果分析

使用以前开发的App做测试,体积20M,使用了multidex。由于app有启动页,本身启动速度已经很快,1s多一点,因此优化效果不够明显。

优化前数据
['465', '1122', '1163']
[['444', '1123', '1149'], ['440', '1150', '1191'], ['410', '1450', '1520'], ['439', '1081', '1112'], ['419', '1072', '1117'], ['409', '1055', '1084'], ['423', '1101', '1135'], ['427', '1079', '1120'], ['465', '1122', '1163']]
apk launcher avarage times:[ThisTime, TotalTime, WaitTime]
[  430.66665649  1137.          1176.77783203]

redex优化后的数据,优化后TotalTime减少70ms
['453', '1129', '1159']
[['403', '1072', '1099'], ['411', '1077', '1123'], ['414', '1056', '1085'], ['383', '1031', '1077'], ['386', '1056', '1102'], ['381', '1030', '1071'], ['449', '1111', '1148'], ['390', '1095', '1127'], ['453', '1129', '1159']]
apk launcher avarage times:[ThisTime, TotalTime, WaitTime]
[  407.777771    1073.          1110.11108398]

结论

Redex可以在Proguard优化后再在dex层面进行优化,Redex需要配置Proguard配置文件来保护一些不应该被优化的类(如JNI调用、反射调用的类等)。
根据实际测试结果看Redex优化后可以提升冷启动速度10%左右,apk体积减少100k左右,低于Facebook给出的数据(25%)。原因可能是我测试的Apk比较简单,本身启动速度已经比较快,后面应该找启动速度慢的App进行优化测试。
普通App建议在做了Proguard优化后,再根据冷启动测试数据决定是否做Redex优化。

参考文章

ReDex github
Optimizing Android bytecode with ReDex
基于 Facebook Redex 实现 Android APK 的压缩和优化
Facebook App 优化工具 ReDex 优化的 6 点及未优化的一大方面

浅谈Android启动时间
怎么计算apk的启动时间?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 准备睡了。 今晚给你发的不知道你有没有看,看了会怎么想,不管了…… 不过发完以后我反而在想,我整天这样也不太...
    晨定阅读 76评论 0 0
  • 小枫是我的铁板闺蜜,她在四川读研究生。前两天,她跟我吐槽,说她实在受不了她的舍友了,我忙问出了什么事,原来,她舍友...
    漫漫Chen阅读 943评论 1 7
  • 自古男儿多豪杰,华夏巾帼亦不让须眉,在历史的烽烟中,她们留下自己浓墨重彩的一笔。从代父从军的花木兰,到击鼓退金兵的...
    准提如是阅读 1,018评论 0 48
  • 目录 -13- 雨没有一刻停歇,阿尔萨斯跪在殿外已经整整两夜了。” “给我滚!永远都不要出现在我面前!” 父亲的话...
    小羡鱼阅读 833评论 12 11