您的位置:首页 > 其它

Dalvik切换到ART时内存地址对齐问题的分析(1)

2016-01-19 20:29 316 查看
AVD启动时打印详细日志信息需要取消 art/runtime/runtime.cc 文件中的374至384行(gLogVerbosity...)的注释。

在之前追踪的函数调用过程中,在文件 art/compiler/driver/compiler_driver.cc 中函数 void CompilerDriver::InitializeClasses(...) 内添加打印dex文件的总数及当前正在初始化第几个dex文件的信息:

2217 ALOGD ("dex_files.size:%d",(int)dex_files.size()); //dex文件的总数

2218 for (size_t i = 0; i != dex_files.size(); ++i) {

2219 const DexFile* dex_file = dex_files[i];

2220 CHECK (dex_file != NULL);

2221 ALOGD ("-27\ti:%d\tLineNum:%d\tFuncName:%s\tFileName:%s",(int)i,__LINE__,__FUNCTION__,__FILE__);//当前正在初始化第 i 个dex文件

2222 InitializeClasses(class_loader, *dex_file, thread_pool, timings);

打印结果:

dex_file.size:15

.......

-27 i:6 LineNum:2221 FuncName:InitializeClasses FileName:art/compiler/driver/compiler_driver.cc

则共有15个dex文件,与启动日志中GenerateImage: /system/bin/dex2oat...这一行中的参数 --dex-file 的个数一致。

根据启动日志可知,出错时正在初始化第6个dex文件(从0开始),可知是初始化第六个--dex-file 参数 --dex-file=/system/framework/framework.jar 指定的jar包时出错。

在文件 art/compiler/driver/compiler_driver.cc 中函数 static void InitializeClass(...) 内添加打印当前正在加载的类的信息:

2121 if(4993 (int)class_def_index) //先用ALOGD打印出来class_def_index的值就是4993,用if语句只是为了方便打印日志。

2122 {

2123 ALOGD ( "\ndescriptor:%s" , descriptor ); //类描述符descriptor表示类class_def的名字

2124 ALOGD ( "class_def_index:%d\tclass_idx_:%d\n" , class_def_index,class_def.class_idx_ ); //class_def_index表示类class_def在类资源区的索引号,class_idx_ 表示类的类型在类型资源区的索引

2125 }

打印结果:

descriptor:Landroid/widget/OverScroller$SplineOverScroller;

class_def_index:4993 class_idx_:4983

发现是在加载类android/widget/OverScroller$SplineOverScroller时出错。

继续在文件 art/runtime/class_linker.cc 中函数 bool ClassLinker::InitializeClass(...) 内的函数 klass->FindDeclaredDirectMethod("<clinit>", "()V") 中(位于文件runtime/mirror/class.cc中)添加打印类加载过程中当前正在执行的方法及其所属的java源文件名和类的信息:

379 if (name mh.GetName() && signature == mh.GetSignature()) {

380 ALOGD ( "i:%d\tname:%s\tnameasstring:%s",i,mh.GetName() ,(char *)(mh.GetNameAsString())); //name表示方法名

381 ALOGD ( "sourcefile:%s\nclassdescriptor:%s\n",mh.GetDeclaringClassSourceFile() , mh.GetDeclaringClassDescriptor());//方法所在的java源文件及所在类

382 return method;

383 }

打印结果:

i:0 name:<clinit> nameasstring:<90><84>ðp

sourcefile:OverScroller.java

classdescriptor:Landroid/widget/OverScroller$SplineOverScroller;

发现方法clinit(类初始化方法)对应于java源文件 frameworks/base/core/java/android/widget/OverScroller.java 中静态类static class SplineOverScroller的初始化。

OverScroller.java对应的.class文件在 out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/widget下,对.class文件用javap -c -p OverScroller$SplineOverScroller反汇编发现生成的文件中没有静态类static class SplineOverScroller对应的java字节码。

经分析,内存地址对齐问题是Zygote进程启动时在加载framework层的类和资源的过程中,执行 dex2oat 时将 OverScroller$SplineOverScroller.class 所对应的jar包 /system/framework/framework.jar 编译成oat文件时出现问题。

对framework.jar文件用dexdump -d framework.jar > framework.txt 反汇编,在 framework.txt 中搜索 "Class #4993" ,即为类 android/widget/OverScroller$SplineOverScroller 对应的dalvik字节码。在其下边的 “Direct Methods" 中找到方法 "<clinit>" 对应的dalvik字节码,在其中可以找到 "div-double/2addr" 这条指令。

JAVA相关知识:

JAVA的静态变量、静态方法、静态类: /content/1089361.html

JVM指令详解(上): /article/2934562.html

JVM指令详解(下): /article/2934563.html

javap(反汇编命令)详解: /article/2934561.html

<init>与<clinit>的区别: /article/7917539.html

java编译生成字节码产生 <init>()与<clinit>()的方法疑问: http://hllvm.group.iteye.com/group/topic/35224
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: