Dalvik虚拟机java方法执行流程和Method结构体分析
Method结构体是啥?
在Dalvik虚拟机内部,每个Java方法都有一个对应的Method结构体,虚拟机根据此结构体获取方法的所有信息.
Method结构体是怎样定义的?
此结构体在不同的android版本稍有变化,但是结构体前面比较重要的一部分(从clazz到nativeFunc)完全没有变化.以下是android4.4.2_r2的Method结构体定义(位于/dalvik/vm/oo/Object.h).
/*
* A method. We create one of these for every method in every class
* we load, so try to keep the size to a minimum.
*
* Much of this comes from and could be accessed in the data held in shared
* memory. We hold it all together here for speed. Everything but the
* pointers could be held in a shared table generated by the optimizer;
* if we're willing to convert them to offsets and take the performance
* hit (e.g. "meth->insns" becomes "baseAddr + meth->insnsOffset") we
* could move everything but "nativeFunc".
*/
struct Method {
/* the class we are a part of */
ClassObject*clazz; /* access flags; low 16 bits are defined by spec (could be u2?) */
u4 accessFlags; /*
* For concrete virtual methods, this is the offset of the method
* in "vtable".
*
* For abstract methods in an interface class, this is the offset
* of the method in "iftable[n]->methodIndexArray".
*/
u2 methodIndex; /*
* Method bounds; not needed for an abstract method.
*
* For a native method, we compute the size of the argument list, and
* set "insSize" and "registerSize" equal to it.
*/
u2 registersSize; /* ins + locals */
u2 outsSize;
u2 insSize; /* method name, e.g. "<init>" or "eatLunch" */
const char* name; /*
* Method prototype descriptor string (return and argument types).
*
* TODO: This currently must specify the DexFile as well as the proto_ids
* index, because generated Proxy classes don't have a DexFile. We can
* remove the DexFile* and reduce the size of this struct if we generate
* a DEX for proxies.
*/
DexProtoprototype; /* short-form method descriptor string */
const char* shorty; /*
* The remaining items are not used for abstract or native methods.
* (JNI is currently hijacking "insns" as a function pointer, set
* after the first call. For internal-native this stays null.)
*/ /* the actual code */
const u2* insns; /* instructions, in memory-mapped .dex */ /* JNI: cached argument and return-type hints */
int jniArgInfo; /*
* JNI: native method ptr; could be actual function or a JNI bridge. We
* don't currently discriminate between DalvikBridgeFunc and
* DalvikNativeFunc; the former takes an argument superset (i.e. two
* extra args) which will be ignored. If necessary we can use
* insns==NULL to detect JNI bridge vs. internal native.
*/
DalvikBridgeFunc nativeFunc; /*
* JNI: true if this static non-synchronized native method (that has no
* reference arguments) needs a JNIEnv* and jclass/jobject. Libcore
* uses this.
*/
bool fastJni; /*
* JNI: true if this method has no reference arguments. This lets the JNI
* bridge avoid scanning the shorty for direct pointers that need to be
* converted to local references.
*
* TODO: replace this with a list of indexes of the reference arguments.
*/
bool noRef; /*
* JNI: true if we should log entry and exit. This is the only way
* developers can log the local references that are passed into their code.
* Used for debugging JNI problems in third-party code.
*/
bool shouldTrace; /*
* Register map data, if available. This will point into the DEX file
* if the data was computed during pre-verification, or into the
* linear alloc area if not.
*/
const RegisterMap* registerMap; /* set if method was called during method profiling */
boolinProfile;
};
struct Method {
ClassObject* clazz;
u4 accessFlags;
u2 methodIndex;
u2 registersSize;
u2 outsSize;
u2 insSize;
const char* name;
DexProto prototype;
const char* shorty;
const u2* insns;
int jniArgInfo;
DalvikBridgeFunc nativeFunc;
bool fastJni;
bool noRef;
bool shouldTrace;
const RegisterMap* registerMap;
bool inProfile;
};
第二个图更容易看
native层的两种引用对象类型
一种是普通的JNI方式,特点是引用对象类型为jobject等样式.第二种就是Dalvik虚拟机内部使用的引用对象类型(Object*,ClassObject*等样式).在虚拟机内部有若干个表存储jobject与Object*的对应关系,因此两者在虚拟机内部可以相互转换.
Dalvik虚拟机眼中的java方法分类
在Dalvik虚拟机看来,java方法分为三类:
1.普通的java方法,即由java代码实现的方法.
2.通过JNI函数实现的native方法,典型的是声明为native的方法.特点是输入参数中的引用对象类型为jobject类型.
3.虚拟机内部实现的native方法.特点是输入参数中的引用对象类型为Object*,ClassObject*等类型.
Dalvik虚拟机是如何执行一个方法的?
以dvmCallMethod为例,其主要执行流程如下图
结论:Method结构体重要成员的意义
结合以上Dalvik虚拟机方法执行流程和对Android源码的分析,得到Method结构体中几个重要成员的意义如下
accessFlags 各个不同标志位表示此方法的多个属性,其中标志位0x00000100表明此方法是native的.
registersSize 该方法总共用到的寄存器个数,包含输入参数所用到的寄存器,还有方法内部另外使用到的寄存器,在调用方法时会为其申请栈内存.
outsSize 该方法调用其他方法时使用到的寄存器个数,注意:只有此方法为非native方法时,此值才有效.
insSize 该方法输入参数用到的寄存器个数(registersSize包含此值)
insns 若方法类型为1,这里指向实际的字节码首地址;若方法类型为2,这里指向实际的JNI函数首地址;若方法类型为3,这里为null.
jniArgInfo 当方法类型为2时有效,记录了一些预先计算好的信息(具体信息格式与实际CPU架构有关,但总是包含返回值类型),从而不需要在调用的时候再通过方法的参数和返回值实时计算了,提高了JNI调用的速度。如果第一位为1(即0x80000000),则Dalvik虚拟机会忽略后面的所有信息,强制在调用时实时计算.
nativeFunc 若方法类型为1,此值无效;若方法类型为2,这里指向dvmCallJNIMethod;若方法类型为3,这里指向实际的处理函数(DalvikBridgeFunc类型).
附录:其余执行方法的函数
void dvmCallMethodA(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, const jvalue* args) 功能与dvmCallMethodV类似,只是参数格式不同而已.
Object* dvmInvokeMethod(Object* obj, const Method* method, ArrayObject* argList, ArrayObject* params, ClassObject* returnType, bool noAccessCheck) 特点在于会根据method的实际输入参数类型argList将输入参数params中的包装类型解包为实际需要的基本类型,并且如果实际返回类型为基本类型它会将结果打包为对应的包装类型返回
void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self)
这里其实就是一个普通的DalvikBridgeFunc函数,当某个方法为JNI实现的native方法时,该方法对应的Method结构体中的nativeFun就指向此函数
它的主要功能就是将Object*样式的引用类型的输入参数转换为JNI格式的jobject样式的引用之后调用dvmPlatformInvokevoid dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
const u4* argv, const char* shorty, void* func, JValue* pReturn)执行时取决于具体的CPU架构,部分采用汇编实现.对于参数argInfo,有的实现确实能够加速方法调用速度(mips,new ARM),有的必须保证argInfo有效(386),有的会忽略(old ARM).
参考资料
Dalvik虚拟机java方法执行流程和Method结构体分析的更多相关文章
- java方法执行流程解析
Java程序运行时,必须经过编译和运行两个步骤.首先将后缀名为.java的源文件进行编译,最终生成后缀名为.class的字节码文件.然后Java虚拟机将编译好的字节码文件加载到内存(这个过程被称为类加 ...
- Dalvik虚拟机JNI方法的注册过程分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8923483 在前面一文中,我们分析了Dalvi ...
- Java 代码执行流程
Java 代码执行流程 类加载过程 加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载 类加载时机:代码使用到这个类时 验证阶段 &qu ...
- 第一章 Java代码执行流程
说明:本文主要参考自<分布式Java应用:基础与实践> 1.Java代码执行流程 第一步:*.java-->*.class(编译期) 第二步:从*.class文件将其中的内容加载到内 ...
- 面试高频SpringMVC执行流程最优解(源码分析)
文章已托管到GitHub,大家可以去GitHub查看阅读,欢迎老板们前来Star! 搜索关注微信公众号 码出Offer 领取各种学习资料! SpringMVC执行流程 SpringMVC概述 Spri ...
- 深入理解Dalvik虚拟机- 解释器的执行机制
Dalvik的指令运行是解释器+JIT的方式,解释器就是虚拟机来对Javac编译出来的字节码,做译码.运行,而不是转化成CPU的指令集.由CPU来做译码,运行.可想而知.解释器的效率是相对较低的,所以 ...
- java控制执行流程
控制执行流程 欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html java当中涉及到的关键字包括if-else.whil ...
- IT兄弟连 Java语法教程 流程控制语句 分支结构语句1
不论哪一种编程语言,都会提供两种基本的流程控制结构:分支结构和循环结构.其中分支结构用于实现根据条件来选择性地执行某段代码,循环结构则用于实现根据循环条件重复执行某段代码.Java同样提供了这两种流程 ...
- IT兄弟连 Java语法教程 流程控制语句 循环结构语句4
do-while循环 Java还有一种循环是do-while.与for.while这些在循环顶部判断条件表达式的语句不同,do-while是在循环底部进行条件表达式的检查.这意味着do-while循环 ...
随机推荐
- struts2 资源国际化
web.xml: <?xml version="1.0" encoding="UTF-8"?><web-app id="WebApp ...
- 断开的管道 java.io.IOException: Broken pipe 解决方法
一.Broken pipe产生原因分析 1.当访问某个服务突然服务器挂了,就会产生Broken pipe; 2.客户端读取超时关闭了连接,这时服务器往客户端再写数据就发生了broken pipe异常! ...
- Linux就业技术指导(五):Linux运维核心管理命令详解
一,Linux核心进程管理命令 1.1 ps:查看进程 1.1.1 命令解释 功能说明 ps命令用于列出执行ps命令的那个时刻的进程快照,就像用手机给进程照了一张照片.如果想要动态地显示进程,就需要使 ...
- Analyzing Microarray Data with R
1) 熟悉CEL file 从 NCBI GEO (http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE24460)下载GSE24460. 将得到 ...
- RNA-seq 安装 fastaqc,tophat,cuffilnks,hisat2
------------------------------------------ 安装fastqc------------------------------------------------- ...
- iperf——网络性能测试工具
一.前言 工作中遇到需要测试Linux服务器网卡占用率的场景,查阅资料后,发现iperf是一款合适的网络测速工具. 下面讲解一下如何使用iperf做网络性能测试. 二.基础知识 先补充一些基础知识: ...
- Ubuntu Server17.10配置静态IP
今天心血来潮,装个虚拟机Ubuntu打算学点东西,遇到了一些问题,同时借助百度的力量解决了,下面是配置的过程. 一. 安装virtualbox 不知道从哪个版本开始,安装虚拟盒子的时候没有了安装虚拟网 ...
- 为什么要学习php
前言: 有的人说java是世界上最伟大的编程语言,也有人说php是最伟大的编程语言,对于这个问题的争论,貌似一直都没有停息过. 前段时间也看过一份编程语言使用排行的调查资料,java当仁不让的保持着排 ...
- nginx 的 upstream timed out 问题
nginx 作为负载服务,表现为网站访问很慢,有些文件或页面要等待到60s才会返回,我注意到60s就是超时时间,但是超时后返回状态是正常值200,网站可以正常打开,就是会一直等待到超时才打开,而且问题 ...
- TPshop学习
笔记大纲: tpshop目录结构 功能模块 函数库 重要配置 助手函数 插件 模板 1.TPshop目录结构 目录结构(来自官方视频截图) 看这个图,目录结构一目了然.下面要讲的内容也是根据这个图展开 ...