ARTIntroductionOverViewARTOverViewART的优点跑分上的提升ART运作原理概述解释执行AOT(Ahead-Of-Time)执行Fork进程的过程32位or64位Forkprocess类的加载及方法调用Oat文件生成及格式类的加载JNI方法及OAT方法的调用常见问题Heap管理(memory分配及回收)分配器回收器分配器及回收器的选择APPENDIX发生NE时,需要提交的Log发生OOM时,抓取hprofCONFIDENTIALBWhyweneedART1.逐条Dex指令解释执行效率低2.GCsuspend时间长3.申请memory时线程竞争4.Memory碎片化严重1.采用AOT技术,运行时执行LocaleCode执行效率高2.GCsuspend时间短3.Memory碎片化轻DVMARTBeforeL随着硬件水平的不断发展,随着人们对高performance的需求,DVM的不足日益突出,促使ART的诞生。CONFIDENTIALBART在跑分上的提升ART运作原理Android对Java的运作流程解释执行源代码Dex代码指令识别实作部分取指令AOT执行直接拷贝了两个寄存器的值,省去了中间的跳转、取指令等操作汇编代码模式选择▪Art默认以本地模式执行,也可以解释模式执行▪如下情况以解释模式执行•通过属性配置▪dalvik.vm.execution-mode•int:portable•intfast•int:jit•JNI方法、抽象方法、proxyClass▪proxyClass是Java机制的动态代理所生成的类由于虚拟机的相关属性都是在首次创建的时候读取的,因此改变了属性之后,需要重启android。可以直接通过开关机的方式,可以通过如下的adb命令实现:adbshellstopadbshellstartFork进程的过程Zygote的启动读取相关property创建虚拟机环境(ART)加载zygoteinit的类退出App_processPreloadclassStartsystemserverWaitforconnection&forkprocess申请heap(mainspace)加载space(imagespace)构建分配器及回收器创建JNI环境32位or64位▪在64位上面可以既运行64位的zygote也可以运行32位的zygote,可以通过ro.zygote进行配置ro.zygote的值Zygote指令集Systemserver指令集套接字名字zygote64Zygote6464zygotezygote32Zygote3232zygotezygote64_32zygote64,zygote3264Zygote64-zygoteZygote32-zygote_secondaryzygote32_64Zygote32,Zygote6432Zygote64-zygote_secondaryZygote32-zygoteForkprocess▪PMS根据一定规则确定一个APP应该运行32位还是64位▪Startprocess时,会依据不同的ABI将请求发给对应的zygotePkgMszygote32ProcessAMSZygote64getabiabiAPP32APP64FORKFORK▪Forkprocess都是通过systemserver的AMS向zygote请求类的加载及方法调用Oat文件的生成▪当系统检测到APP对应的dex文件还没有对应的odex文件和其对应,此时会通过dex2oat进行AOT操作,生成OAT文件。▪所生成的文件位于/data/dalvik-cache/inst目录下:▪查看oat文件中的内容,可以通过Android提供的oatdump进行:OAT文件的格式▪OAT文件本质是一个ELF文件,但文件结构不同于一般的ELF文件。类方法的本地方法指令HeaderSectionHeaderrodataoatexecSections/SegmentsOatlastwordRawdexfilesOatclasses结束的标志Rodata区的格式▪如右边的格式所示dex_file_location_sizedex_file_location_datadex_file_checksumdex_file_offsetmethods_offsets_pointer………………methods_offsets_pointerStatusTypeOatMethodOffsetsDexFile……DexFileInstructionsetdexfilecountDexFileInfosOatclass………OatClassOatMethodOffset……OatMethodOffseNativeCodecode_offset_gc_map_offset_类的加载▪ART虚拟机刚创建时,会预先加载一些类,如:•com_android_dex_Dex•dalvik_system_PathClassLoader•java_lang_BootClassLoader•java_lang_ClassLoader•java_lang_Object•java_lang_RuntimeException•……•java_lang_Throwable_stackTrace▪之后的类都通过classloader进行加载▪BootClassLoader加载位于bootclassPath中的类▪不同的classloader视为不同的类classloaderBaseDexClassLoaderPathClassLoader保存着dexFileListloadClassART方法的调用▪当虚拟机被创建好之后,通过如下的JNI函数打开了Java的世界:▪在这个函数中调用到了ArtMehtod.invoke函数▪然后调用了统一入口点:staticvoidCallStaticVoidMethod(JNIEnv*env,jclass,jmethodIDmid,...)entry_point_from_quick_compiled_code_quick_to_interpreter_bridge_quick_resolution_trampoline_quick_generic_jni_trampoline_Quick_compile_code例如,当前方法是一个静态方法,那么就会进入_resolution_trampoline,先初始化其所在的类,然后,在执行对应的函数。当需要使用解释器执行,则其值为quick_to_interpreter_bridge,直接进入解释器当函数为Native函数时,则值为quick_generic_jni_trampoline_,先查找Native入口点,后执行正常会直接进入被翻译的入口点执行根据入口点的值不一样,进入不同的函数执行JNI方法调用▪首先在已经加载库中查找方法▪方法名字格式为:▪每一个库被加载时,会调用其中的OnLoad函数,从而可以在JNI_OnLoad函数注册Jni函数Java_com_android_TestClass_TestFunciont注册的实质是找到这个NativeMethod的结构描述,并重设entry_point_from_jni_ReferenceTable▪JNI接口中提供了申请object或者数组的接口,由于Native代码的局部变量并不会入栈,GC的时候可能将这些memory回收掉。为了解决这个问题ART引入了Referencetable。如下为运作机制:NativeCodeNewObjectobjectReferenceTable申请object存入table返回编号GetFieldJNI接口对object数据的操作ReferenceTable包括:GloableReferenceTable,保存全局的引用,需要通过NewGlobalRef,DeleteGlobalRef完成添加删除,最大元素个数51200LocalReferenceTable,保存局部引用,通过NewLocalRef和DeleteLocalRef实现添加和删除,最大元素个数512。通过NewObject,NewXXXArray的方式会自动添加,随着Native的栈帧弹出,而自动释放。常见问题—GlobalReferenceOverflow▪判断是GlobalReference溢出▪确认是哪一个对象特别多▪Check代码是否存在Leak的情况▪如果check不到需要打开art/runtime/Android.mk中打开MTK_DEBUG_REF_TABKE宏常见的问题—classnotfound▪Classnotfound•明确类所在的文件有被加载▪除了bootclasspath中的类,都需要显式指定路径▪要运行APP的包,PMS会给出路径DexPathList给出了成功打开的路径,如果文件打开失败不在里面的常见的问题—loadlibrary形如下面的Log表示找不到定义类的数据,一般就是这个类确实没有定义,或者对应文件打开失败•确认没有异常发生▪如果初始化类的过程有异常发生也会导致类加载失败。例如执行static代码段中有异常抛出父类没加载成功▪Unsatisfiedlinkerror/nosuchmethoderror▪要明确库中方法的名字是否按规则写,如果采用注册的方式那么要注意签名要一致ARTMemory托管Memory托管•Java代码并不需要关注memory的申请和释放,可以把精力用在算法实现上•art首先会用mmap获得足够空间,这些空间在没有使用的时候并不占用物理内存,在使用的时候才分配物理内存,在不需要的时候还能及时归还给系统•ART会将这些空间托管给不同的算法,进行管理,对于一些算法有如下的一些优点:▪减少碎片化▪减少申请memory时线程之间的竞争缺点:不易调试•ART回收memory时也实现了不同的算法,会依据进程状态选择不同的算法,较之于DVM时:▪GC时对线程挂起的时间缩短ART使用的Allocator▪ART会将映射到的space托管给不同的分配器,目前支持的分配器如下:AllocatorDescriptionSpaceRosAlloctorRunsOfSpaceAllocatorMainspaceTLABThreadLocalAllocationBlockBumpPointerspaceBumpPointerHeadtoendAllocationBumpPointerspaceDLMallocMainspaceLOSLargeObjectofSpaceAllocatorLargeobjectofspaceRosAlloctor和dlmalloc的切换需要在代码中实现:位于./art/runtime/gc/Heap.h中的staticconstexprboolkUseRosAlloc,目前默认值为true,即默认使用RosAllocAllocator—RosAlloc▪RosAlloc的分配策略slotsBitmap1:allocbitmap,每用掉一个slot,就标记对应的slot位Bitmap2:bulk_free_bitmap,GC时,批释放时用到Bitmap2:thread_local_free_bitmap,GC时,单独释放时用到……………………………………………Headerbitmap1bitmap2bitmap3Run1RunsRunAllocator—BumpPointer▪分配策略•每一次申请时,返回end的值•将end移动size的对齐字节后,作为下一次申请object的首地址,即end总是指向下一个object的首地址•不计数申请,直到发生outofmemory•采用MovingGC的方式endAllocator—TLAB▪ThreadLocalAllocatio