一种基于Dalvik虚拟机JNI机制中接口函数性能优化方法

xiaoxiao2020-7-22  9

一种基于Dalvik虚拟机JNI机制中接口函数性能优化方法【专利摘要】本发明涉及一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法。本发明包括:在目标接口函数的适当位置植入数据索引机制;获取目标数据的标识常量并调用哈希函数计算标识常量的哈希值;根据哈希值在内建哈希表查找目标表项,如存在则直接返回目标数据地址;根据目标数据常量标识,调用原系统函数查找目标数据,如找到则将目标数据以及其标识常量的哈希值插入内建哈希表中并正确返回;否则抛出异常并返回。采用本发明所提供的优化技术方案对JNI机制接口函数GetMethodID、GetStaticMethodID进行优化后,性能表现全面优于原接口函数,性能提升幅度较大,在一定程度上可以提高Dalvik虚拟机整体性能。【专利说明】—种基于DaIVik虚拟机JNI机制中接口函数性能优化方法【
技术领域
】[0001]本发明涉及一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法。【
背景技术
】[0002]Android是由Google公司基于移动设备而开发的嵌入式系统,具有优良的性能表现以及较低的硬件配置需求,因此迅速成为目前移动终端之上的主流操作系统。这种优势的体现主要得益于Google对作为Android系统基石的Dalvik虚拟机所做出的大量优化。实际上,Dalvik虚拟机并不是一个标准的Java虚拟机,因为它并不符合标准Java虚拟机设计规范。Dalvik虚拟机是一个针对嵌入式系统中低速CPU和内存受限的等特点,经过专门设计优化而实现的Java语言虚拟机。[0003]JNI机制的英文全称为JavaNativeInterface,是SUN公司所定义的一套编程框架标准接口,用于实现Java代码和本地代码互相调用的需求。本地代码是指那些使用Java语言之外的编程语言编写的代码,与本地硬件平台相关。在Android系统中,由Dalvik虚拟机实现了这套接口,供Dalvik虚拟机的Java应用与本地代码实现互相调用,使Java应用的执行效率得到了很大提高。[0004]即便如此,在使用本地调用机制编写应用程序的时候,除了本地代码执行的高效性带来的优点之外,Dalvik虚拟机在Java代码和本地代码互相调用过程中也付出了额外的开销。尤其是当本地函数需要多次访问Java类中的同一个函数时,每次调用JNI接口函数都会执行同样的查找工作以获得对应的MethodID数据。事实上,这些重复的冗余操作是可以避免的。【
发明内容】[0005]本发明的目的在于提供一种提高Dalvik虚拟机整体性能的基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法。[0006]本发明的目的是这样实现的:[0007](I)在目标接口函数的适当位置植入数据索引机制;[0008](2)获取目标数据的标识常量并调用哈希函数计算标识常量的哈希值;[0009](3)根据哈希值在内建哈希表查找目标表项,如存在则直接返回目标数据地址,否则实施步骤(4);[0010](4)根据目标数据常量标识,调用原系统函数查找目标数据,如找到则将目标数据以及其标识常量的哈希值插入内建哈希表中并正确返回;否则抛出异常并返回。[0011]步骤(I)中目标接口函数适当位置是指:对于GetMethodID函数,适当位置为GetMethodID函数调用dvmFindVirtualMethodHierByDescriptor函数对目标MethodID查找之前,在此处引入一个数据索引机制;对于GetStaticMethodID函数,适当位置为GetStaticMethodID函数调用dvmFindDirectMethodHierByDescriptor函数对目标MethodID查找之前。[0012]步骤(2)中目标数据的标识常量是指目标方法所属类的描述符、目标方法名以及签名数据;其中计算标识常量的哈希值是指,调用Dalvik虚拟机提供的哈希函数计算目标数据标识常量字符串哈希值。[0013]步骤(3)中内建哈希表是指,一个哈希表数据结构HashTable,每一个哈希单元包括三个成员变量,分别用于存储标识常量的哈希值、标识常量的字符拼接以及目标方法的MethodID。[0014]步骤(3)中根据该哈希值在内建哈希表查找目标表项是指,根据步骤21)中生成的哈希值在内建哈希表中查找匹配目标表项并返回目标方法的MethodID。[0015]步骤(4)中根据目标数据常量标识,调用原系统函数查找目标数据是指,当步骤(3)的返回值为空时,接口函数将会调用原系统函数并根据目标数据常量标识查找目标方法的MethodID,其中对于接口函数GetMethodID,原系统函数为[0016]dvmFindVirtualMethodHierByDescriptor函数;对于接口与函数GetStaticMethodID,原系统函数为dvmFindDirectMethodHierByDescriptor函数。[0017]步骤(4)将目标数据以及其标识常量的哈希值插入内建哈希表是指,当步骤(3)返回值为空时,接口函数GetMethodID或GetStaticMethodID通过原系统函数查找到目标方法的MethodID数据后,将MethodID数据和与之对应的常量标识以及常量标识的哈希值插入内建哈希表中。[0018]发明的有益效果在于:[0019]在实施过程中发现,采用本发明所提供的优化技术方案对JNI机制接口函数GetMethodID^GetStaticMethodID进行优化后,性能表现全面优于原接口函数,性能提升幅度较大,在一定程度上可以提高Dalvik虚拟机整体性能,发明有益效果十分之明显。【专利附图】【附图说明】[0020]图1为原接口函数执行流程概况图;[0021]图2为改进后接口函数执行流程概况图;[0022]图3为原GetMethodID和GetStaticMethodID接口函数执行流程;[0023]图4为改进后的GetMethodID和GetStaticMethodID接口函数执行流程;[0024]图5为GetMethodID和GetMethodIDhs执行时间随函数数量变化图;[0025]图6为GetStaticMethodID和GetStaticMethodIDhs执行时间随静态函数数量变化图;[0026]图7为优化前后的本地调用接口函数执行时间。【具体实施方式】[0027]下面结合附图对本发明做进一步描述。[0028]基于Dalvik虚拟机的JNI机制中的两个接口函数GetMethodID和GetStaticMethodID在执行查找目标方法MethodID数据时,由于无法将已被查到的数据进行持久化保存,因此该接口函数会根据虚拟机的执行需要可能会对某一数据进行多次的查找操作,这就造成大量冗余的查找操作,在一定程度上影响了Dalvik虚拟机的执行效率。同时,在查找的过程中需要遍历目标方法所属Java类的方法表,当Java类中方法数较多时,性能的消耗也相应更多。本发明正是针对这一问题,公开了一种基于Dalvik虚拟机JNI机制的性能优化技术方案。该技术方案在目标功能接口原有工作流程的基础上,在其中某一恰当位置引入一个采用哈希散列技术实现的数据索引机制,使得在不改变目标接口功能的前提下,将已被查找过的数据保存在一个内建哈希表中,当该数据再次被查找时,将会中内建哈希表中直接取用,避免再次调用相关的查找函数执行查找操作。通过实施这种方案,可以有效地消除GetMethodID和GetStaticMethodID接口函数在执行过程中所在的大量冗余操作,大幅度提高了其性能表现。实验表明,采用本技术方案对上述两个接口函数进行优化后,性能提升幅度可达近35%。该技术解决方案的工作可以划分为以下三个步骤:[0029]步骤1:获取目标数据的标识常量并调用哈希函数计算该标识常量的哈希值;[0030]步骤2:根据该哈希值在内建哈希表查找目标表项,如存在则直接返回目标数据地址,否则实施步骤3;[0031]步骤3:根据目标数据常量标识,调用原系统函数查找目标数据,如找到则将目标数据以及其标识常量的哈希值插入内建哈希表中并正确返回;否则抛出异常并返回。[0032]在本发明中所涉及的一类JNI接口函数的主要功能为:当本地函数访问Java类方法时,需要调用该接口函数查找相应目标方法的MethodID。其实现原理简述为:当本地函数传入目标Java类资源的基本描述信息后,接口函数将根据相关信息在对应的资源列表中获取目标资源的ID数据。在这个过程中,如果目标资源所属的Java类若尚未被虚拟机加载并初始化,那么接口函数还需先完成上述工作,再进行ID数据的查找,以上工作流程如附图1所示。该类接口函数一共包含两个,分别为GetMethodID和GetStaticMethodID函数。GetMethodID函数用于获取Java类中非静态方法MethodID数据;GetStaticMethodID函数用于获取Java类中静态方法MethodID数据。[0033]下面以查找某一特定Java类方法(该方法非静态方法,同时该类非为接口类)的MethodID为例,进一步描述该函数内部的执行流程,描述如下:虚拟机首先向接口函数GetMethodID传入目标方法的描述信息,主要包括目标方法所属类的描述符、目标方法名以及签名数据,随后接口函数将会判断目标资源所属的Java类尚未被虚拟机加载并初始化,如是则根据目标方法名以及签名数据首先调用dvmFindVirtualMethodHierByDescriptor函数在VirtualMethod(虚方法)表中查找目标方法,如有则返回相应的MethodID;否则将调用dvmFindDirectMethodByDescriptor函数在DirectMethod(直接方法)表中查找目标方法,如有则返回相应的MethodID,否则抛出异常并返回空值,以上工作流程如附图3所/Jnο[0034]从接口函数GetMethodID的执行流程中可以发现,如果某Java类的某一特定方法的被调用次数较多,那么相同的查找操作将会被多次执行,这就是前面所提到的冗余操作。同时这类查找操作所需的性能消耗会随着Java类中方法数量的增加而增加。[0035]而本发明要解决的技术问题就是,提供一种技术方案,消除前面提到的大量冗余查找所带来的性能消耗,以达到进一步提高本地调用机制的执行效率的目的。[0036]为解决上述技术问题,本发明提供了一种针对JNI机制的优化技术方案,其作用原理是:在原有接口函数特定位置中引入一个数据索引机制,当某一特定的MethodID在第一次被引用后,系统将该数据的物理地址经过散列处理并存入一个内建的哈希表中,如该数据在后续程序执行过程中再次被系统查找调用时,系统将直接从哈希表中取得目标数据的物理地址,以达到避免二次调用查找函数的目的,以上工作流程如附图2所示。该技术方案的实现是建立在前面所述的理论基础之上,将该数据索引机制插入至原有接口函数中一个恰当的位置,使之在不影响原接口函数功能的基础上消除冗余操作,提高接口执行效率。在一定程度上,该插入点位置的选择是本发明的关键所在,因此本说明在此以接口函数GetMethodID为例进行介绍。[0037]根据前面针对接口函数GetMethodID实现原理的介绍,可以知道该接口函数GetMethodID在验证目标方法所属类是否被加载并初始化后,将会开始具体的查找工作。因此将数据索引机制在此弓丨入,使改进后的接口函数GetMethodID将首先在内建哈希表中查找目标方法的MethodID,若有将直接返回该MethodID;否则将进行原接口的常规的查找流程,并将结果插入内建哈希表中。这样就实现了“一次查找,多次使用”的设计思想,进而避免了重复的查找操作,提高了接口性能。[0038]本发明针对原JNI本地接口GetMethodID、GetStaticMethodID进行了优化。实验表明,相较于原本地接口函数性能均提高近35%。[0039]该技术解决方案的工作可以主要划分为以下三个步骤:[0040]步骤1:获取目标数据的标识常量并调用哈希函数计算该标识常量的哈希值;[0041]步骤2:根据该哈希值在内建哈希表查找目标表项,如存在则直接返回目标数据地址;否则实施步骤3;[0042]步骤3:根据目标数据常量标识,调用原系统函数查找目标数据,如找到则将目标数据以及其标识常量的哈希值插入内建哈希表中并正确返回;否则抛出异常并返回。[0043]所述步骤I中的哈希函数沿用了Dalvik虚拟机提供的哈希函数,Dalvik虚拟机提供的哈希函数是hash=hash*31+*utf8Str++,hash变量初始为1,循环取得urf8Str的每一个字符进行运算,如下所示。[0044]while(*utf8Str!='\0')[0045]hash=hash*31+*utf8Str++;[0046]哈希函数的传入参数为要查找的Java函数或Java变量的名字和签名的连接字符串。循环对字符串的每一个字符进行运算,返回计算得到的哈希函数值。将哈希函数值对哈希表表长进行取模运算,即得到哈希单元的编号。[0047]所述步骤2中的内建哈希表实际上是对在Dalvik虚拟机所定义的哈希表数据结构HashTable的一个扩展,在原哈希表数据结构HashTable中,每一个哈希单元包括两个成员变量,hashValue和data,分别用来存储哈希值和数据。但根据本优化方案的需求,必须有一个数据已知的成员变量来处理冲突,所以对原HashTable数据结构进行了扩展,向哈希单元中添加了一个新的字符指针成员key,用来存储字段变量名字和签名的字符串连接。修改后的哈希表源码如下:[0048]structmHashTable{[0049]inttableSize;/*mustbepowerof2*/[0050]intnumEntries;/^currentSof^live^entries*/[0051]intnumDeadEntries;/*current#oftombstoneentries氺/[0052]mHashEntry*pEntries;/*arrayonheap氺/[0053]HashFreeFuncfreeFunc;[0054]pthread_mutex_tlock;[0055]};[0056]structmHashEntry{[0057]u4hashValue;[0058]void*data;[0059]char*key;[0060]};[0061]所述哈希表的冲突处理为如果两个或两个以上方法的哈希函数值映射为同一个哈希值,则为发生了冲突。在向哈希表存储数据时,首先判断对应的哈希值的单元的data成员是否为空,如果为空,则直接存入方法的指针,否则,发生了冲突,向前移动一个单元继续判断,直到找到data成员为空的哈希单元,存入数据。从哈希表取出数据时,为了避免冲突的影响,保证哈希函数值hashValue相等的同时,还要保证key字段一致。如果哈希函数值一致,而key不一致,说明产生了冲突,则向前移动一个哈希单元再次比较。比较key字段需要使用字符串比较函数strcmp,为了降低计算开销,应尽量缩短key的长度。令每一个类都有一个哈希表,而不是设置一个全局的哈希表,就是为了达到key字段尽量简短的目的。[0062]所述步骤3中原系统函数指代的是原接口函数中负责具体查找操作的功能函数。当目标数据不在哈希表中,将会调用原系统函数查找获取目标MethodID数据。其中对于接口函数GetMethodID,其原系统函数为dvmFindVirtualMethodHierByDescriptor函数;对于接口与函数GetStaticMethodID,其原系统函数为dvmFindDirectMethodHierByDescriptor函数。[0063]将该技术技术方案引入到原接口函数适当位置后,将有效提高原接口函数的执行效率,同时也不会对原接口功能有任何改变。优化后的接口函数的完整工作流程如附图2所示:[0064]步骤一:接口函数在执行之初将首先接收传入的参数,主要包括主要包括目标方法所属类的描述符、目标方法名以及签名数据,其中所属类的描述符用于标识目标方法所属的Java类、目标方法名和签名数据作为目标方法的唯一标识。在目标方法所属Java类的方法表中,虚拟机可以通过目标方法名和签名数据即可找到目标方法的MethodID数据。[0065]步骤二:在正确接收入口参数后,接口函数将根据参数-所属类的描述符,判断虚拟机是否已加载该Java类,如果尚未加载该Java类,将调用相关的类加载函数完成该Java类的加载工作;否则,进入下一工作步骤。类加载工作的意义在于,虚拟机需要将目标Java类的数据读入并解析,然后再其内部的运行时环境中生成一个目标类的实例对象。随后,虚拟机才可以通过该实例对象对该类的相关数据进行操作使用,而这一读入解析的过程称为类的加载。[0066]步骤三:若目标方法所属的Java类已经被正确加载,接口函数将根据另外两个入口参数-目标方法名和签名数据,在内建哈希表中查找目标方法的MethodID数据,并将查找结果进行返回。内建哈希表的定义在前面已经叙述,再此不再赘述。[0067]步骤四:当接口函数完成了在内建哈希表中查找目标数据的工作后,将对查找结果进行非空判断:若该结果非空,则表示已经查找到目标数据,该数据将被接口函数返回,接口函数工作结束;否则表示内建哈希表中尚未保存该目标数据,接口函数将调用原系统函数在目标方法所属Java类中的方法表中,对目标方法的MethodID数据进行常规的查找工作-即步骤五,并将查找结果进行返回。[0068]步骤五:常规的查找工作结束后,接口函数将对查找结果进行非空判断,若查找结果非空,则表示查找到目标方法的MethodID数据,该数据随后将被插入到内建哈希表中并将该数据作为接口函数的返回值进行返回,若虚拟机再次访问该数据时,将从内建哈希表中直接取出,而不用再调用原系统函数进行查找;若查找结果为空,接口函数将抛出异常并返回。[0069]本实施所基于的测试环境是Android4.0.4,其中Dalvik虚拟机的使用JNI本地接口函数GetMethodID和GetStaticMethodID(当函数为静态函数时)来获得函数的MethodID,上述接口函数定义位于Dalvik虚拟机源码路径:dalvik/vm/jn1.cpp。[0070]实施时,具体如附图4所示,接口函数首先判断目标方法的所属类是否已被虚拟机加载,如是则跳过这一步,否则将调用dvmlnitClass(clazz)函数对该类进行加载并初始化。然后判断内建哈希表是否创建,如是则进行下一步操作,否则创建内建哈希表。[0071]实施时,具体如附图4所示,所述连接字符串name和sig,构建key是指,将入口参数name变量(字符型数组,用于表示目标方法名)以及sig变量(字符型数组,用于表示签名)进行字符串拼接并存入methodkey变量(字符型数组,用于表示目标方法名和签名的字符串连接)。[0072]实施时,具体如附图4所示,所述在哈希表中查找目标数据,并返回ID是指,接口函数在得到methodkey变量后,将调用函数dvmComputeUtf8mHash并以methodkey变量作为参数计算对应的哈希值并将结果保存在hashvalue变量中,随后将调用函数dvmmHashTableLookup在内建哈希表中查找目标数据。其函数功能描述如下:dvmmHashTabIeLookup(mHashTabIe^pHashTable,u4itemHash,char*key,HashCompareFunccmpFunc)实现哈希表的查找功能,参数cmpFunc为哈希比较函数,这里为strcmp,用来比较key成员字段。根据计算得到的哈希值itemHash定位到指定的哈希单元,如果data成员非空,并且itemHash成员和key成员分别各自相等,那么就找到指定ID,可直接使用。[0073]实施时,具体如附图4所示,在函数列表中查找目标数据是指,当dvmmHashTableLookup函数返回值为空时,接口函数将调用原系统函数在对应的函数列表中查找目标数据。其中对于接口函数GetMethodID,其原统函数为dvmFindVirtualMethodHierByDescriptor函数;对于接口与函数GetStaticMethodID,其原系统函数为dvmFindDirectMethodHierByDescriptor函数。[0074]实施时,具体如附图4所示,判断查找结果是否为空是指,判断原系统函数的返回值是否为空。若为空,则表示目标方法不存在于当前Java类,系统将抛出异常并返回;若为非空,则表示正确找到目标方法数据,该数据将做为接口函数的返回值。其中对于接口函数GetMethodID,本步骤用于判断dvmFindVirtualMethodHierByDescriptor函数返回值是否为空;对于接口函数GetStaticMethodID,本步骤用于判断dvmFindDirectMethodHierByDescriptor函数返回值是否为空。[0075]实施时,具体如附图4所示,将结果插入哈希表是指,若dvmFindVirtualMethodHierByDescriptor函数或dvmFindDirectMethodHierByDescriptor函数的返回值非空时,接口函数将调用dvmmHashTabIeAdd函数将返回值插入内建哈希表。[0076]在上述实施过程中所使用到的功能函数中,dvmmHashTabIeLookup以及dvmmHashTabIeAdd函数为本发明依据优化需求自行开发的功能函数,其余为Dalvik虚拟机原功能函数。[0077]dvmmHashTabIeLookup函数用于在内建哈希表中匹配查找目标方法数据的FieldID,其函数代码如下:[0078]void*dvmmHashTabIeLookup(mHashTabIe^pHashTabIeju4itemHash,char^key,HashCompareFunccmpFunc)[0079]{[0080]mHashEntry^pEntry;[0081]mHashEntry*pEnd;[0082]void*resu11=NULL;[0083]assert(pHashTable->tableSize>0);[0084]/^jumptothefirstentryandprobeforamatch氺/[0085]pEntry=&pHashTable->pEntries[itemHash&(pHashTable->tableSize-l)];[0086]pEnd=&pHashTable->pEntries[pHashTable->tableSize];[0087]whiIe(pEntry->data!=NULL){[0088]if(pEntry->data!=HASH—T0MBST0NE&&[0089]pEntry->hashValue==itemHash&&[0090](*cmpFunc)(pEntry->key,key)==0)[0091]{[0092]/*match*/[0093]//LOGD("+++matchonentry%d",pEntry-pHashTable->pEntries);[0094]break;[0095]}[0096]pEntry++;[0097]if(pEntry==pEnd){/^wraparoundtostart木/[0098]if(pHashTabIe->tabIeSize==I)[0099]break;/^edgecase-single-entrytable*/[0100]pEntry=pHashTable->pEntries;[0101]}[0102]}[0103]result=pEntry->data;[0104]returnresult;[0105]}[0106]dvmmHashTableAdd函数用于将一个目标方法的相关数据信息(包括字段描述信息的哈希值、字段描述信息以及字段对应的FieldID),其函数代码如下:[0107]voiddvmmHashTabIeAdd(mHashTabIe^pHashTabIeju4itemHash,char^key,void^item)[0108]{[0109]mHashEntry^pEntry;[0110]mHashEntry*pEnd;[0111]assert(pHashTable->tableSize>0);[0112]assert(item!=HASH_T0MBST0NE);[0113]assert(item!=NULL);[0114]/^jumptothefirstentryandprobeforamatch氺/[0115]pEntry=&pHashTable->pEntries[itemHash&(pHashTable->tableSize-l)];[0116]pEnd=&pHashTable->pEntries[pHashTable->tableSize];[0117]whiIe(pEntry->data!=NULL){[0118]pEntry++;[0119]if(pEntry==pEnd){/^wraparoundtostart木/[0120]if(pHashTabIe->tabIeSize==I)[0121]break;/^edgecase-single-entrytabled/[0122]pEntry=pHashTable->pEntries;[0123]}[0124]//LOGI("+++lookprobing%d...",pEntry-pHashTable->pEntries);[0125]}[0126]if(pEntry->data==NULL){[0127]pEntry->hashValue=itemHash;[0128]pEntry->data=item;[0129]memcpy(pEntry->key,key,strlen(key));[0130]pHashTable->numEntries++;[0131]/*[0132]氺Weiveaddedanentry.Seeifthisbringsustooclosetofull.[0133]*/[0134]if((pHashTabIe->numEntries+pHashTabIe->numDeadEntries)*L0AD—DENOM[0135]>pHashTable_>tableSize*LOAD—NUMER)[0136]{[0137]if(!resizemHash(pHashTable,pHashTable_>tableSize*2)){[0138]/^donitreallyhaveawaytoindicatefailure氺/[0139]LOGE("Dalvikmhashresizefailure");[0140]dvmAbort();[0141]}[0142]/^note^pEntry^isnowinvalid木/[0143]}else{[0144]}[0145]/^fulltableisbad__searchfornonexistentneverhalts氺/[0146]assert(pHashTable->numEntries<pHashTable->tableSize);[0147]}[0148]}[0149]本方案在实施过程表现出了较好优化效果,下面是优化后接口函数性能测试结果展示:[0150]本发明中所采用的测试用例主要用于测试GetMethodID、GetStaticMethodID两个接口函数优化前后的性能。测试用例在执行过程中将频繁调用GetMethodID或GetStaticMethodID函数获取某一目标数据,以此来模拟出大量冗余操作,用于考察采用优化方案的接口函数是否可以有效地提高系统性能。[0151]由于接口函数获取Java类中MethodID时需要遍历访问对应的函数列表,列表的长度的大小对于查找效率有很大影响,因此通过增减Java类中函数数量,用以测试在不同的函数数量的情况下优化前后的本地调用接口获取MethodID时间变化,以达到全面衡量接口函数的优化质量。[0152]还需要指出的是:当接口函数在Java类的函数列表查找目标数据时,若目标数据在查找列表中位置相对靠前,那么接口函数所消耗时间就相对较短,反之则较长。因此为了减小目标数据在查找列表中位置的不同所引起的影响,测试用例要求对于查找列表中的每一个函数,其被查找的次数相同,同时测试结果为查找各个函数平均查找时间。[0153](I)测试结果:[0154]基准测试程序的Java类包含有10个普通函数、10个静态函数,分别调用2个接口函数获取Java类中每个MethodID,每个接口函数执行30000次,运行测试程序50次,计算每个接口函数的平均耗时,实验结果如下表所示,附图7中时间单位为ms。附图7展示了优化之前和优化之后各个接口函数的执行时间,以及优化之后相对于优化之前的时间变化。[0155]由于接口函数在查找目标数据时,需要遍历Java类的函数列表来查找目标Java类的函数列表,因此Java类的函数的数量直接影响了优化前后查找方式的查找效率。为了进一步展示优化效果,在基准测试程序的基础上,改变Java类中的函数的数量并重复进行多组测试,以达到全面定量分析接口优化后的性能情况。[0156]接口函数GetMethodID定量测试结果如附图5所示,其中GetMethodID指代原接口函数,GetMethodIDhs指代优化后接口函数。[0157]接口函数GetStatiMethodID定量测试结果如附图6所不,其中GetStatiMethodID指代原接口函数,GetStaticMethodIDhs指代优化后接口函数。[0158](2)结果分析:[0159]对于前面的基准测试用例,其测试数据如表I所示,原接口函数GetMethodID、GetStaticMethodID与改进优化后的接口函数的执行消耗时间差别较为明显,改进优化后的接口函数的加速比分别为1.37、1.35,改进优化效果较好,性能较之前提高近35%。[0160]在定量分析测试阶段中,从少到多逐渐增加测试用例中的函数的数量,得出接口函数执行时间变化曲线,附图5和附图6分别为接口函数GetMethodID和GetStaticMethodID改进优化之前和改进优化之后的接口函数查找执行时间随Java类的函数数量变化对比曲线图。如附图5和附图6所示,当Java类中函数数量在3个之内时,改进之前的接口函数GetMethodID(GetStaticMethodID)和改进之后的接口函数GetMethodIDhs(GetStaticMethodIDhs)的查找执行时间相差不多,而改进后接口函数GetMethodIDhs(GetStaticMethodIDhs)的执行时间略快于改进前接口函数GetMethodID(GetStaticMethodID)ο当Java类中函数数量由3个开始增多时,接口函数查找MethodID的执行时间开始增多,但是原接口GetMethodID(GetStaticMethodID)的执行时间要比改进后接口函数GetMethodIDhs(GetStaticMethodIDhs)的执行时间增长得更快,改进优化后的接口函数的加速比越来越大,优化性能越来越大,当Java类包含8个函数时,加速比平均为1.31,当Java类中函数数量为14时,加速比达到1.53,可见改进优化后的接口函数GetMethodIDhs和GetStaticMethodIDhs的优化性能随着Java类中函数数量的增多而增大。【权利要求】1.一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:(1)在目标接口函数的适当位置植入数据索引机制;(2)获取目标数据的标识常量并调用哈希函数计算标识常量的哈希值;(3)根据哈希值在内建哈希表查找目标表项,如存在则直接返回目标数据地址,否则实施步骤(4);(4)根据目标数据常量标识,调用原系统函数查找目标数据,如找到则将目标数据以及其标识常量的哈希值插入内建哈希表中并正确返回;否则抛出异常并返回。2.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(I)中目标接口函数适当位置是指:对于GetMethodID函数,适当位置为GetMethodID函数调用dvmFindVirtualMethodHierByDescriptor函数对目标MethodID查找之前,在此处引入一个数据索引机制;对于GetStaticMethodID函数,适当位置为GetStaticMethodID函数调用dvmFindDirectMethodHierByDescriptor函数对目标MethodID查找之前。3.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(2)中目标数据的标识常量是指目标方法所属类的描述符、目标方法名以及签名数据;其中计算标识常量的哈希值是指,调用Dalvik虚拟机提供的哈希函数计算目标数据标识常量字符串哈希值。4.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(3)中内建哈希表是指,一个哈希表数据结构HashTable,每一个哈希单元包括三个成员变量,分别用于存储标识常量的哈希值、标识常量的字符拼接以及目标方法的MethodID。5.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(3)中根据该哈希值在内建哈希表查找目标表项是指,根据步骤21)中生成的哈希值在内建哈希表中查找匹配目标表项并返回目标方法的MethodID。6.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(4)中根据目标数据常量标识,调用原系统函数查找目标数据是指,当步骤(3)的返回值为空时,接口函数将会调用原系统函数并根据目标数据常量标识查找目标方法的MethodID,其中对于接口函数GetMethodID,原系统函数为dvmFindVirtualMethodHierByDescriptor函数;对于接口与函数GetStaticMethodID,原系统函数为dvmFindDirectMethodHierByDescriptor函数。7.根据权利要求1所述的一种基于Dalvik虚拟机JNI机制中接口函数GetMethodID和GetStaticMethodID性能优化方法,其特征在于:所述步骤(4)将目标数据以及其标识常量的哈希值插入内建哈希表是指,当步骤(3)返回值为空时,接口函数GetMethodID或GetStaticMethodID通过原系统函数查找到目标方法的MethodID数据后,将MethodID数据和与之对应的常量标识以及常量标识的哈希值插入内建哈希表中。【文档编号】G06F9/455GK104035809SQ201410177666【公开日】2014年9月10日申请日期:2014年4月29日优先权日:2014年4月29日【发明者】吴艳霞,张国印,谢东良,许圣明,王彦彰申请人:哈尔滨工程大学

最新回复(0)