Android Dalvik 虚拟机介绍

2023-10-25 11:40

本文主要是介绍Android Dalvik 虚拟机介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

bd464143f4a3145d8c53b039309a2e40.gif

和你一起终身学习,这里是程序员Android

经典好文推荐,通过阅读本文,您将收获以下知识点:

1.Java 语言在Android 上运行流程
2.虚拟机发展过程
3.Android Dalvik 模式
4.Android N 中dex2oat 原理以及模式
5.如何判断dex2oat 采用的相关参数
6.如何查看dex2oat 的log
7.什么时候进行dex2oat
8.手机反应慢的原因
9.解决手机反应慢的方法
10.参考文献

1.Java 语言在Android 上运行流程

7f82d6ae38d802efa8308b76375ae590.jpeg

Java语言在android 运行流程

2.虚拟机发展过程

  • 1.初期Dalvik

  • 2.中期Dalvik

  • 3.后期ART模式

    为了让APK在不同的虚拟机都可以运行,Google 采取了适配器模式,在让虚拟机运行之前先执行 dexopt ,即将dex 文件优化成odex 文件,可以让虚拟机更加优化的执行。

    在ART 虚拟机中,dexopt 将dex文件优化成二进制格式的问题,从而可以让ART虚拟机执行。
    dexopt 会调用dex2oat 进行优化,dex2oat 的任务是将原来的dex文件进行预翻译,从而可以加快app运行的时间,但是由于某些app比较复杂,所以优化的时间就比较长。
    优化是以dex 文件中的Method 方法为单位,dex2oat 在优化时候,会根据需求优化一定量的Method,即不是所有的Method 都回翻译成oat模式。

3.Android Dalvik 模式

根据优化Method量的多少分的模式

62c0a6a31f15b84994e85bcbf0151825.jpeg

Android Dalvik

4. Android N 中dex2oat 原理以及模式

N版本当中强化了JIT模式。JIT模式是Just in time 的简称。意思是在运行的时候,根据method有使用频率来决定是否要对某一个方法进行优化。虚拟机会统计每一个方法被执行的次数。如果某一个方法执行的次数比较多,达到一定的阈值,就会将升级为hot method,并将其记录在一个profile当中。在系统空闲并且在充电的时候,只将这些方法进行优化。在运行的时候,也会对这些方法进行优化,以方便在运行的时候使用。

  • 1.Android N dex2oat 模式图

ae37535b1613d6d83281d871f7b91740.jpeg

Android N dex2oat 模式图

  • 2.Android N dex2 oat 原理图

16cfdcac91cbd24b463de7b68c306d01.jpeg

Android N dex2oat 原理图

5. 如何判断dex2oat 采用的相关参数

dex2oat 的参数会在代码中通过如下函数打印

  • 1.L 版本

L版本会无条件打印

timings.StartTiming("dex2oat Setup");
1436  LOG(INFO) << CommandLine();
  • 2 . M 和N版本

在M和N当中会有条件的打印不同的内容。
例如在会在debug版本中打印非常详细的dex2oat参数,而在非debug版本中打印部分内容。

if (kIsDebugBuild || dex2oat.IsImage() || dex2oat.IsHost() || !kIsTargetBuild) {
2144    LOG(INFO) << CommandLine();
2145  } else {
2146    LOG(INFO) << StrippedCommandLine();
2147  }

6.如何查看dex2oat 的log

搜索关键字

  • dex2oat

  • dex-file
    被优化的dex 文件信息

  • oat-fd

  • oat-location
    oat 存放位置

  • compiler-filter
    判断采用的那种优化模式

eg1:

01-01 04:28:03.471265  5654  5654 I dex2oat : Starting dex2oat.01-01 04:28:37.548439  5654  5654 I dex2oat : dex2oat took 34.077s (threads: 4) arena alloc=23MB java alloc=14MB native alloc=88MB free=5MB 01-01其中:dex2oat tokk 34.077s表示 dex2oat的耗时情况,(threads:4)表示,一共用了4个线程做这件事情。

eg2:

01-01 08:34:27.063 I/dex2oat ( 7714): /system/bin/dex2oat --runtime-arg -classpath 
--runtime-arg --instruction-set=arm --instruction-set-features=default --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art 
--dex-file=/data/data/com.tencent.mm/app_dex/secondary-2.dex.jar --oat-fd=62 --oat-location=/data/data/com.tencent.mm/app_cache/secondary-2.dex.dex 
--runtime-arg -Xms64m --runtime-arg -Xmx512m  --compiler-filter=speedM 和 N 版本,可以通过会打印出较多的dex2oat参数。上面的Log中,可以得出很多信息来:
1.被优化的dex文件信息,可以通过 --dex-file获取,形如上面我们就知道优化的是微信里面的内容,因为--dex-file参数的dex文件位于com.tencent.mm目录下面的。
2.优化之后oat存储的位置,可以看到--oat-location其是保存在包名下面的app_cache目录下面的。
3.是对插件优化还是对APK本身优化。在L的时候所有的PMS优化的内容都会放在data/dalvik-cache目录下面,所以如果oat放的位置是data/dalvik-cache目录下面,那么就是优化主APK,否则就是优化插件的。而在M和N当中,优化的结果会放在自己的包下面,但是不会是这种类似app_cache这种,根据这个可以判断是对插件的优化。
4.优化采用的模式根据--compiler-filter可以判断采用的是哪种模式。如果我们关注的信息没有打印出来,可以修改上面打印这些Log的条件。

7.什么时候进行dex2oat

dex2oat一般发生在如下的时候:

  • 第一次开机

当第一次开机的时间,PackageManagerService会扫描手机中的各个目录,
当检测到APK之后,就会执行安装流程,在安装的时候,就会对这些APP进行dex2oat操作。
如果说APP比较多,或者dex2oat比较慢,那么开机时间就会比较长。
  • 安装APP

当系统开机之后,我们安装APP的时候,也会进dex2oat。
实质上这时候也是走到了PackageManagerService的流程。
由PMS执行安装的运行,并发起dex2oat的动作。
  • 优化插件

当APP运行的时候,会根据自己的需要,优化自己需要的插件文件。
例如自己引用到的非系统类的jar包。

综上来看,系统执行dex2oat的主解有两类,一类是system server中的Packagemanagerservice发起的并让installd执行的;另一类是APP自身根据需要优化自己的插件。

8. 手机反应慢的原因

慢的原因如下

  • 工作量
    dex2oat发生的时候,会将原文件中的dex文件抽出来,逐个指令的判断,然后进行翻译,并生成大量的中间内容。并占用所有有CPU(目前的策略是有多少个核,就启动多少个线程)

  • CPU
    如果CPU越多,则启动的线程数越多,这样的话,就会比较快做完。

  • EMMC
    如果dex文件比较大,会产生大量的中间内容,这些在memory当中是保存不下的,所以采用了swap机制,会将一些内容交换到EMMC当中,而且有大量的读操作,同时会将结果保存至emmc当中,所以emmc的性能也是非常关键的。

  • Memory
    如上面所述,memory越少,越容易发生交换,所以就会引起IO上的瓶颈。

  • Patch
    google之前有一个优化,就是在dex2oat做完的时候,不进行析构,因为析构会将交换出去的内容再读进来,从而导致耗时较长。
    1.M版本的patch为:
    ALPS02736915
    2.N版本当中,暂时没有

9. 解决手机反应慢的方法

遇到慢的问题的时候,先从上面几个方面找原因,如果无法解决,那么就只好调整APP的安装策略。例如原来为speed模式,就改为interpreter-only模式。
参考修改方法如下:

  • 1. N版本(L /M 不适用) 在PMS中添加白名单

/frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java

private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter) {//在这函数中,可以判断传递下来的pkg是否是我们需要的package,如果是的话,将targetCompilerFilter设置为speed-profile。//speed-profile会在安装的时候采用interperter-only,然后,运行一段时间之后,会将那些常用的方法优化成为speed模式。也就是说是有选择性的优化。if (isProfileGuidedFilter && isUsedByOtherApps(pkg)) {checkProfiles = false;targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {throw new IllegalStateException(targetCompilerFilter);}isProfileGuidedFilter = false;
}// If we're asked to take profile updates into account, check now.
boolean newProfile = false;###  mtk add beginif(pkg.contains("com.tencent.mm")){targetCompilerFilter="interpret-only";}
### mtk add end
  • 2.在Installd中进行白名单处理
    适用于 L M N 版本
    实现思路

//1.通过 property来增加白名单
//注意Facebook是apk的名字,后面不用带后缀,但是大小写一定要匹配。
adb shell setprop ro.mtk.dex2oat_white_list Facebook://2.如果需要增加到开机启动当中,可以如下修改在device.mk中加入
//多个APK名字之间用冒号隔开。
PRODUCT_PROPERTY_OVERRIDES += ro.mtk.dex2oat_white_list=facebook:Facebook:youtube:skype:twitter:

修改点
\frameworks\native\cmds\installd\commands.c

static int shouldUseInterpretonly(const char* input_file_name);static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
bool vm_safe_mode)
{......######## MTK add start
//适当的时候,进行调用if(shouldUseInterpretonly(input_file_name))
{
strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
have_dex2oat_compiler_filter_flag = true;   //关键是设置这个参数的值
ALOGW("%s is in whitelist from property so set interpret-only",input_file_name);
}
######## MTK add end
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);.....}
######MTK add start
/**
*函数功能,根据input的file name判断,当前来优化的APK名字判断是否在白名单当中。
*白名单来自于property
*/
static int shouldUseInterpretonly(const char* input_file_name)
{
char prop_buf[PROPERTY_VALUE_MAX];
memset(prop_buf,0,PROPERTY_VALUE_MAX);
bool have_whitelist = property_get("ro.mtk.dex2oat_white_list", prop_buf, NULL) > 0;
if(!have_whitelist)
return false;
char *str = prop_buf;
char appname[128],*ptrname = appname;
memset(appname,0,128);while(*str)
{
if(*str != ':')
{
*ptrname = *str;
ptrname ++;
str++;
}
else{str++;if(*appname != 0)
{
if(strstr(input_file_name,appname)) //found
{
return 1; 
}
else
{
memset(appname,0,sizeof(appname));
ptrname = appname;
}
}
}
}
return 0;
}
### MTK add end
  • 3 . 在dex2oat.cc 中进行白名单处理

/art/dex2oat/dex2oat.cc
由于插件不会走PMS和installd这一路,所以,只能想办法在dex2oat中进行拦截。在这里面需要解决的问题是:如何判断来优化的就是我们关注的插件。

  • 通过判断dex2oat进程的父pid来判断是插件
    如果是插件进行的dex2oat,有一个特点就是这个进程的父进程不是installd。所以可以根据一点进行判断。但是有一个特点,会将所有的插件全部优化成interpreter-only。

以N版本为例,建议的代码如下:

/**调整编译的模式,规则:如果当前进程的父进程是installd,不做修改,否则修改为interpreter-only。*因为插件类的,都是进程本来fork的dex2oat.*only for device end**/void adjustCompilerOptions(const CompilerOptions* compiler_options){int ppid = getppid(); //获取当前进程的parent pidchar cmdline_path[256];char contents[256];memset(cmdline_path,0,sizeof(cmdline_path));memset(contents,0,sizeof(contents));snprintf(cmdline_path,"/proc/%d/cmdline");FILE *fd = fopen(cmdline_path,"r"); // 打开proc/pid/cmdline文件,以读取对应ppid进程的名字if(fd == NULL){LOG(ERROR) < return;}fgets(contents,sizeof(contents),fd); //读取文件中的内容fclose(fd);if(strstr(contents,"installd")){ //判断是否是installdreturn;}Log(INFO)<<"parent is not installd,may be is a plugin adjust it to interpret-only";compiler_options->SetCompilerFilter(kInterpretOnly); //如果是的话,强行调整编译模式为interpreteronly模式}在ParseArgs函数中对dex2oat的模式进行调整:ProcessOptions(parser_options.get());// Insert some compiler things.InsertCompileOptions(argc, argv);if(!IsHost())  //注意一定要判断非host端,否则会有问题adjustCompilerOptions(compiler_options_.get());}
  • 根据dex文件名字或者oatlocation名字来判断

L版本:
/art/dex2oat/dex2oat.cc方法1:// mtk add beginif ((!oat_filename_.empty() && (oat_filename_.find("facebook") != std::string::npos))||(!zip_location_.empty() && (zip_location_.find("facebook") !=std::string::npos))||((!oat_location_.empty()) && oat_location_.find("facebook") != std::string::npos)){  // mtk modify 2016-06-06compiler_filter_string = "interpret-only";LOG(INFO) <<" This apk is in whitelist from property so set interpret-only ";}// mtk add endif (compiler_filter_string = nullptr){compiler_filter_string = "speed";}注意:CTS测项用的包不能使用interpret-only模式,因为一些CTS测项是性能相关的,如果改为interpret模式,会导致CTS不过。之前有客户为了追求更快的安装速度,将所有的包都改为interpret-only的,结果CTS就不过了,针对这种情况,可以把CTS的包再放到speed模式的白名单当中。cts的关键字为test.方法2(若上述方法无效):1420 if (num_methods <= compiler_options_->GetNumDexMethodsThreshold()) {
1421 compiler_options_->SetCompilerFilter(CompilerOptions::kSpeed);
1422 VLOG(compiler) << "Below method threshold, compiling anyways";
1423 }
1424 }
1425
1426//mtk_add_begin
1427 static constexpr size_t kMinCompileDexSize = 4;
1428 if (!image_ && dex_files_.size() > kMinCompileDexSize) {
1429 compiler_options_->SetCompilerFilter(CompilerOptions::kInterpretOnly);
1430 LOG(INFO) << "Enable Whitelist Rules. Current Dex File Sizes:" << dex_files_.size();
1431 }
1432//mtk_add_end
1433
1434 return true;
1435 }
1436
1437 // Create and invoke the compiler driver. This will compile all the dex files.
1438 void Compile() {
1439 TimingLogger::ScopedTiming t("dex2oat Compile", timings_);
1440 compiler_phases_timings_.reset(new CumulativeLogger("compilation times"))

或者如下

[SOLUTION L版本]在device.mk中加入PRODUCT_PROPERTY_OVERRIDES += ro.mtk.dex2oat_white_list=com.tencent.mm: (注意 包名后又冒号“:”[添加source code](抱歉不能排版)/art/dex2oat/dex2oat.cc添加红色部分:#ifdef HAVE_ANDROID_OSextern "C"{static int shouldUseInterpretonly(const char* filename){char prop_buf[92];memset(prop_buf,0,92);bool have_whitelist = property_get("ro.mtk.dex2oat_white_list", prop_buf, NULL) > 0;if(!have_whitelist)return false;char *str = prop_buf;char appname[128],*ptrname = appname;memset(appname,0,128);while(*str)
{if(*str != ':'){*ptrname = *str;ptrname ++;str++;} else{str++;if(*appname != 0){if(strstr(filename,appname)) //found{return 1; } else{memset(appname,0,sizeof(appname));ptrname = appname;}}}
}return 0;
}
}
#endifstatic int dex2oat(int argc, char** argv) {std::string dex_filename; //mtk_add......if (option.starts_with("--dex-file=")) {dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());dex_filename = option.substr(strlen("--dex-file=")).data(); //mtk_add} else if......if (compiler_filter_string == nullptr) { if (instruction_set == kMips64) {// TODO: fix compiler for Mips64.compiler_filter_string = "interpret-only";} else if (image) {compiler_filter_string = "speed";} else {#if ART_SMALL_MODEcompiler_filter_string = "interpret-only";#else#ifdef HAVE_ANDROID_OSif(shouldUseInterpretonly(zip_location.c_str())){compiler_filter_string = "interpret-only";LOG(INFO) <<" This apk is in whitelist from property so set interpret-only";}else if(shouldUseInterpretonly(dex_filename.c_str())){compiler_filter_string = "interpret-only";LOG(INFO) <<" This jar is in whitelist from property so set interpret-only";}else{#endifcompiler_filter_string = "speed";#ifdef HAVE_ANDROID_OS} #endif
#endif }
}CHECK(compiler_filter_string != nullptr);
.......}

参考文献:

【腾讯文档】Android Framework 知识库
https://docs.qq.com/doc/DSXBmSG9VbEROUXF5

友情推荐:

Android 开发干货集锦

至此,本篇已结束。转载网络的文章,小编觉得很优秀,欢迎点击阅读原文,支持原创作者,如有侵权,恳请联系小编删除,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

3a2996a13a3aafb7b0838b1c2e4168dd.jpeg

点击阅读原文,为大佬点赞!

这篇关于Android Dalvik 虚拟机介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/282326

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk