dex2oat与应用安装时间优化

背景

  • 4.4之前,android使用dalvik虚拟机,采用JIT(Just-in-time 即时编译),在运行时将字节码即时翻译成机器码再执行

  • 5.0开始,android使用art虚拟机,采用AOT(Ahead Of Time 运行前编译),在安装时将字节码(.dex)翻译成机器码(.oat)再执行,提高运行时效率

  • 由于dex2oat过程涉及 读取dex -> 以类为粒度编译 -> 生成许多中间文件 ->合并为.oat(odex)文件 所以EMMC性能 ,CPU性能, swap区大小, 等硬件性能在一定程度上决定了编译的速度, 而3561平台性能较弱,编译时间的增加直接的造成安装时间提高, 同时应用的热更新包编译会占据一定的cpu资源造成系统卡顿,直接影响用户体验,本文主要从灵活修改dex2oat调度策略来优化dex2oat过程,而没有减少dex2oat时间

优化

1.对与安装应用,根据应用的方法数来决定是否执行dex2oat

  • 如果对所有应用强制不进行dex2oat,能一劳永逸,将安装时间压缩到最低,但是这违背了art虚拟机设计的初衷

  • 虽然很多市场上的app体积比较大,但是除去资源文件,他的类数量和方法数量不一定像体积那么大,对于方法数,
    较小的应用,去做dex2oat的优化是有必要的,因为与dex2oat时间产生直接关系的是方法数而不是apk体积

  • 我们希望在3561平台上将所有应用的安装时间控制在1分钟以内,经过测试和统计,执行dex2oat在一分钟左右的应用方法数在110000左右,所以对于方法数在110000以下的应用执行dex2oat,对方法数在110000以上的应用禁止dex2oat,以达到性能和安装时间均衡的状态

commands.cpp# 从property中获取dex2oat方法数边界值bool have_dex2oat_num_dex_methods_flag = property_get("fly.dex2oat.num_dex_methods",                                                              dex2oat_num_dex_methods_flag, NULL) > 0;# 设置--num-dex-methods参数,if(have_dex2oat_num_dex_methods_flag){        sprintf(dex2oat_num_dex_method_arg, "--num-dex-methods=%s", dex2oat_num_dex_methods_flag);    }dex2oat.cc   if (!image_ &&      compiler_options_->IsCompilationEnabled()) {      size_t num_methods = 0;      for (size_t i = 0; i != dex_files_.size(); ++i) {        const DexFile* dex_file = dex_files_[i];        CHECK(dex_file != nullptr);        num_methods += dex_file->NumMethodIds();      }      # GetNumDexMethodsThreshold()获取--num-dex-methods参数if (num_methods != 0       && compiler_options_->GetNumDexMethodsThreshold() != 0       && num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {        # 方法数小于--num-dex-methods则设置为kSpeed,执行dex2oat        compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);      }else{          # 方法数大于--num-dex-methods则设置为kInterpretOnly,禁止dex2oat    compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);      }    }

2.对与应用插件,限制对插件执行dex2oat的线程数

热更新不可能直接把java源码下发,只能下发dex文件,在本地把基线dex给反编译然后合并再回编译很明显不可能,毕竟baksmali.jar和smali.jar加起来都快5m了,热更新框架不可能搞这么大。但是利用dex2oat的这个特性,我们可以只下发包括更新代码的dex,客户端接收后把新dex作为classes.dex,旧dex作为classes2.dex,送进dex2oat,就能得到一个更新过代码的oat文件,尽可能简单的完成热更新。

作者:琴梨梨

链接:https://www.jianshu.com/p/cf63266cca86

插件下发时,dex2oat默认会开启和cpu核心数相同的线程数去编译,占据非常的的cpu资源,很容易会造成系统卡顿

插件一般会下载到APP的私有数据目录,即 “data/data/” 或 “data/user/” ,而使用dex2oat时会把dex的源路径作为参数传入,根据参数有无包含这两个路径可以判断是否是一个插件在调用dex2oat,如果是的话则限制dex2oat的线程数为1,保证热更新的正常和系统的流畅

 dex2oat.cc    for (const char* dex_file_name : dex_filenames_) {std::string fileNameStr(dex_file_name);        if(fileNameStr.find("data/user/") != std::string::npos || fileNameStr.find("data/data/") != std::string::npos)        {  compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);  # 限制线程数为1          thread_count_ = 1;  break;}      }

更多相关文章

  1. 下载Android Sdk源码方法
  2. Android 自定义属性时TypedArray的使用方法
  3. Android TV 智能电视/盒子 APP 开发焦点控制 两种方法实例
  4. android v7包 正常导入使用方法
  5. Could not find *****/adb.exe!的解决方法(android sdk太新了?**#
  6. 转帖并消化:Android中一种使用AttributeSet自定义控件的方法
  7. android 时间同步
  8. Android Inflate()方法用途

随机推荐

  1. Android之四大组件(AIDL Service的使用)
  2. Android inject input events 注入Touch
  3. Flex开发Android(安卓)更改ViewMenu外观
  4. Deepin Linux系统中开启ap-hotspot wifi
  5. 【Android开发小记--9】触摸事件---实现
  6. Android自定义view三验证码输入控件
  7. android 输入法界面显示的开关
  8. Android和IOS开发资料
  9. Android setLayerType 硬件加速问题
  10. android studio中.9.png图片处理