一種基于Dalvik虛擬機JNI機制中接口函數(shù)性能優(yōu)化方法【專利摘要】本發(fā)明涉及一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法。本發(fā)明包括:在目標接口函數(shù)的適當位置植入數(shù)據(jù)索引機制;獲取目標數(shù)據(jù)的標識常量并調(diào)用哈希函數(shù)計算標識常量的哈希值;根據(jù)哈希值在內(nèi)建哈希表查找目標表項,如存在則直接返回目標數(shù)據(jù)地址;根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù),如找到則將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表中并正確返回;否則拋出異常并返回。采用本發(fā)明所提供的優(yōu)化技術(shù)方案對JNI機制接口函數(shù)GetMethodID、GetStaticMethodID進行優(yōu)化后,性能表現(xiàn)全面優(yōu)于原接口函數(shù),性能提升幅度較大,在一定程度上可以提高Dalvik虛擬機整體性能。【專利說明】—種基于DaIVik虛擬機JNI機制中接口函數(shù)性能優(yōu)化方法【
技術(shù)領(lǐng)域:
】[0001]本發(fā)明涉及一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法?!?br>背景技術(shù):
】[0002]Android是由Google公司基于移動設(shè)備而開發(fā)的嵌入式系統(tǒng),具有優(yōu)良的性能表現(xiàn)以及較低的硬件配置需求,因此迅速成為目前移動終端之上的主流操作系統(tǒng)。這種優(yōu)勢的體現(xiàn)主要得益于Google對作為Android系統(tǒng)基石的Dalvik虛擬機所做出的大量優(yōu)化。實際上,Dalvik虛擬機并不是一個標準的Java虛擬機,因為它并不符合標準Java虛擬機設(shè)計規(guī)范。Dalvik虛擬機是一個針對嵌入式系統(tǒng)中低速CPU和內(nèi)存受限的等特點,經(jīng)過專門設(shè)計優(yōu)化而實現(xiàn)的Java語言虛擬機。[0003]JNI機制的英文全稱為JavaNativeInterface,是SUN公司所定義的一套編程框架標準接口,用于實現(xiàn)Java代碼和本地代碼互相調(diào)用的需求。本地代碼是指那些使用Java語言之外的編程語言編寫的代碼,與本地硬件平臺相關(guān)。在Android系統(tǒng)中,由Dalvik虛擬機實現(xiàn)了這套接口,供Dalvik虛擬機的Java應(yīng)用與本地代碼實現(xiàn)互相調(diào)用,使Java應(yīng)用的執(zhí)行效率得到了很大提高。[0004]即便如此,在使用本地調(diào)用機制編寫應(yīng)用程序的時候,除了本地代碼執(zhí)行的高效性帶來的優(yōu)點之外,Dalvik虛擬機在Java代碼和本地代碼互相調(diào)用過程中也付出了額外的開銷。尤其是當本地函數(shù)需要多次訪問Java類中的同一個函數(shù)時,每次調(diào)用JNI接口函數(shù)都會執(zhí)行同樣的查找工作以獲得對應(yīng)的MethodID數(shù)據(jù)。事實上,這些重復的冗余操作是可以避免的。【
發(fā)明內(nèi)容】[0005]本發(fā)明的目的在于提供一種提高Dalvik虛擬機整體性能的基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法。[0006]本發(fā)明的目的是這樣實現(xiàn)的:[0007](I)在目標接口函數(shù)的適當位置植入數(shù)據(jù)索引機制;[0008](2)獲取目標數(shù)據(jù)的標識常量并調(diào)用哈希函數(shù)計算標識常量的哈希值;[0009](3)根據(jù)哈希值在內(nèi)建哈希表查找目標表項,如存在則直接返回目標數(shù)據(jù)地址,否則實施步驟(4);[0010](4)根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù),如找到則將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表中并正確返回;否則拋出異常并返回。[0011]步驟(I)中目標接口函數(shù)適當位置是指:對于GetMethodID函數(shù),適當位置為GetMethodID函數(shù)調(diào)用dvmFindVirtualMethodHierByDescriptor函數(shù)對目標MethodID查找之前,在此處引入一個數(shù)據(jù)索引機制;對于GetStaticMethodID函數(shù),適當位置為GetStaticMethodID函數(shù)調(diào)用dvmFindDirectMethodHierByDescriptor函數(shù)對目標MethodID查找之前。[0012]步驟(2)中目標數(shù)據(jù)的標識常量是指目標方法所屬類的描述符、目標方法名以及簽名數(shù)據(jù);其中計算標識常量的哈希值是指,調(diào)用Dalvik虛擬機提供的哈希函數(shù)計算目標數(shù)據(jù)標識常量字符串哈希值。[0013]步驟(3)中內(nèi)建哈希表是指,一個哈希表數(shù)據(jù)結(jié)構(gòu)HashTable,每一個哈希單元包括三個成員變量,分別用于存儲標識常量的哈希值、標識常量的字符拼接以及目標方法的MethodID。[0014]步驟(3)中根據(jù)該哈希值在內(nèi)建哈希表查找目標表項是指,根據(jù)步驟21)中生成的哈希值在內(nèi)建哈希表中查找匹配目標表項并返回目標方法的MethodID。[0015]步驟(4)中根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù)是指,當步驟(3)的返回值為空時,接口函數(shù)將會調(diào)用原系統(tǒng)函數(shù)并根據(jù)目標數(shù)據(jù)常量標識查找目標方法的MethodID,其中對于接口函數(shù)GetMethodID,原系統(tǒng)函數(shù)為[0016]dvmFindVirtualMethodHierByDescriptor函數(shù);對于接口與函數(shù)GetStaticMethodID,原系統(tǒng)函數(shù)為dvmFindDirectMethodHierByDescriptor函數(shù)。[0017]步驟(4)將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表是指,當步驟(3)返回值為空時,接口函數(shù)GetMethodID或GetStaticMethodID通過原系統(tǒng)函數(shù)查找到目標方法的MethodID數(shù)據(jù)后,將MethodID數(shù)據(jù)和與之對應(yīng)的常量標識以及常量標識的哈希值插入內(nèi)建哈希表中。[0018]發(fā)明的有益效果在于:[0019]在實施過程中發(fā)現(xiàn),采用本發(fā)明所提供的優(yōu)化技術(shù)方案對JNI機制接口函數(shù)GetMethodID^GetStaticMethodID進行優(yōu)化后,性能表現(xiàn)全面優(yōu)于原接口函數(shù),性能提升幅度較大,在一定程度上可以提高Dalvik虛擬機整體性能,發(fā)明有益效果十分之明顯?!緦@綀D】【附圖說明】[0020]圖1為原接口函數(shù)執(zhí)行流程概況圖;[0021]圖2為改進后接口函數(shù)執(zhí)行流程概況圖;[0022]圖3為原GetMethodID和GetStaticMethodID接口函數(shù)執(zhí)行流程;[0023]圖4為改進后的GetMethodID和GetStaticMethodID接口函數(shù)執(zhí)行流程;[0024]圖5為GetMethodID和GetMethodIDhs執(zhí)行時間隨函數(shù)數(shù)量變化圖;[0025]圖6為GetStaticMethodID和GetStaticMethodIDhs執(zhí)行時間隨靜態(tài)函數(shù)數(shù)量變化圖;[0026]圖7為優(yōu)化前后的本地調(diào)用接口函數(shù)執(zhí)行時間。【具體實施方式】[0027]下面結(jié)合附圖對本發(fā)明做進一步描述。[0028]基于Dalvik虛擬機的JNI機制中的兩個接口函數(shù)GetMethodID和GetStaticMethodID在執(zhí)行查找目標方法MethodID數(shù)據(jù)時,由于無法將已被查到的數(shù)據(jù)進行持久化保存,因此該接口函數(shù)會根據(jù)虛擬機的執(zhí)行需要可能會對某一數(shù)據(jù)進行多次的查找操作,這就造成大量冗余的查找操作,在一定程度上影響了Dalvik虛擬機的執(zhí)行效率。同時,在查找的過程中需要遍歷目標方法所屬Java類的方法表,當Java類中方法數(shù)較多時,性能的消耗也相應(yīng)更多。本發(fā)明正是針對這一問題,公開了一種基于Dalvik虛擬機JNI機制的性能優(yōu)化技術(shù)方案。該技術(shù)方案在目標功能接口原有工作流程的基礎(chǔ)上,在其中某一恰當位置引入一個采用哈希散列技術(shù)實現(xiàn)的數(shù)據(jù)索引機制,使得在不改變目標接口功能的前提下,將已被查找過的數(shù)據(jù)保存在一個內(nèi)建哈希表中,當該數(shù)據(jù)再次被查找時,將會中內(nèi)建哈希表中直接取用,避免再次調(diào)用相關(guān)的查找函數(shù)執(zhí)行查找操作。通過實施這種方案,可以有效地消除GetMethodID和GetStaticMethodID接口函數(shù)在執(zhí)行過程中所在的大量冗余操作,大幅度提高了其性能表現(xiàn)。實驗表明,采用本技術(shù)方案對上述兩個接口函數(shù)進行優(yōu)化后,性能提升幅度可達近35%。該技術(shù)解決方案的工作可以劃分為以下三個步驟:[0029]步驟1:獲取目標數(shù)據(jù)的標識常量并調(diào)用哈希函數(shù)計算該標識常量的哈希值;[0030]步驟2:根據(jù)該哈希值在內(nèi)建哈希表查找目標表項,如存在則直接返回目標數(shù)據(jù)地址,否則實施步驟3;[0031]步驟3:根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù),如找到則將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表中并正確返回;否則拋出異常并返回。[0032]在本發(fā)明中所涉及的一類JNI接口函數(shù)的主要功能為:當本地函數(shù)訪問Java類方法時,需要調(diào)用該接口函數(shù)查找相應(yīng)目標方法的MethodID。其實現(xiàn)原理簡述為:當本地函數(shù)傳入目標Java類資源的基本描述信息后,接口函數(shù)將根據(jù)相關(guān)信息在對應(yīng)的資源列表中獲取目標資源的ID數(shù)據(jù)。在這個過程中,如果目標資源所屬的Java類若尚未被虛擬機加載并初始化,那么接口函數(shù)還需先完成上述工作,再進行ID數(shù)據(jù)的查找,以上工作流程如附圖1所示。該類接口函數(shù)一共包含兩個,分別為GetMethodID和GetStaticMethodID函數(shù)。GetMethodID函數(shù)用于獲取Java類中非靜態(tài)方法MethodID數(shù)據(jù);GetStaticMethodID函數(shù)用于獲取Java類中靜態(tài)方法MethodID數(shù)據(jù)。[0033]下面以查找某一特定Java類方法(該方法非靜態(tài)方法,同時該類非為接口類)的MethodID為例,進一步描述該函數(shù)內(nèi)部的執(zhí)行流程,描述如下:虛擬機首先向接口函數(shù)GetMethodID傳入目標方法的描述信息,主要包括目標方法所屬類的描述符、目標方法名以及簽名數(shù)據(jù),隨后接口函數(shù)將會判斷目標資源所屬的Java類尚未被虛擬機加載并初始化,如是則根據(jù)目標方法名以及簽名數(shù)據(jù)首先調(diào)用dvmFindVirtualMethodHierByDescriptor函數(shù)在VirtualMethod(虛方法)表中查找目標方法,如有則返回相應(yīng)的MethodID;否則將調(diào)用dvmFindDirectMethodByDescriptor函數(shù)在DirectMethod(直接方法)表中查找目標方法,如有則返回相應(yīng)的MethodID,否則拋出異常并返回空值,以上工作流程如附圖3所/Jnο[0034]從接口函數(shù)GetMethodID的執(zhí)行流程中可以發(fā)現(xiàn),如果某Java類的某一特定方法的被調(diào)用次數(shù)較多,那么相同的查找操作將會被多次執(zhí)行,這就是前面所提到的冗余操作。同時這類查找操作所需的性能消耗會隨著Java類中方法數(shù)量的增加而增加。[0035]而本發(fā)明要解決的技術(shù)問題就是,提供一種技術(shù)方案,消除前面提到的大量冗余查找所帶來的性能消耗,以達到進一步提高本地調(diào)用機制的執(zhí)行效率的目的。[0036]為解決上述技術(shù)問題,本發(fā)明提供了一種針對JNI機制的優(yōu)化技術(shù)方案,其作用原理是:在原有接口函數(shù)特定位置中引入一個數(shù)據(jù)索引機制,當某一特定的MethodID在第一次被引用后,系統(tǒng)將該數(shù)據(jù)的物理地址經(jīng)過散列處理并存入一個內(nèi)建的哈希表中,如該數(shù)據(jù)在后續(xù)程序執(zhí)行過程中再次被系統(tǒng)查找調(diào)用時,系統(tǒng)將直接從哈希表中取得目標數(shù)據(jù)的物理地址,以達到避免二次調(diào)用查找函數(shù)的目的,以上工作流程如附圖2所示。該技術(shù)方案的實現(xiàn)是建立在前面所述的理論基礎(chǔ)之上,將該數(shù)據(jù)索引機制插入至原有接口函數(shù)中一個恰當?shù)奈恢?,使之在不影響原接口函?shù)功能的基礎(chǔ)上消除冗余操作,提高接口執(zhí)行效率。在一定程度上,該插入點位置的選擇是本發(fā)明的關(guān)鍵所在,因此本說明在此以接口函數(shù)GetMethodID為例進行介紹。[0037]根據(jù)前面針對接口函數(shù)GetMethodID實現(xiàn)原理的介紹,可以知道該接口函數(shù)GetMethodID在驗證目標方法所屬類是否被加載并初始化后,將會開始具體的查找工作。因此將數(shù)據(jù)索引機制在此弓丨入,使改進后的接口函數(shù)GetMethodID將首先在內(nèi)建哈希表中查找目標方法的MethodID,若有將直接返回該MethodID;否則將進行原接口的常規(guī)的查找流程,并將結(jié)果插入內(nèi)建哈希表中。這樣就實現(xiàn)了“一次查找,多次使用”的設(shè)計思想,進而避免了重復的查找操作,提高了接口性能。[0038]本發(fā)明針對原JNI本地接口GetMethodID、GetStaticMethodID進行了優(yōu)化。實驗表明,相較于原本地接口函數(shù)性能均提高近35%。[0039]該技術(shù)解決方案的工作可以主要劃分為以下三個步驟:[0040]步驟1:獲取目標數(shù)據(jù)的標識常量并調(diào)用哈希函數(shù)計算該標識常量的哈希值;[0041]步驟2:根據(jù)該哈希值在內(nèi)建哈希表查找目標表項,如存在則直接返回目標數(shù)據(jù)地址;否則實施步驟3;[0042]步驟3:根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù),如找到則將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表中并正確返回;否則拋出異常并返回。[0043]所述步驟I中的哈希函數(shù)沿用了Dalvik虛擬機提供的哈希函數(shù),Dalvik虛擬機提供的哈希函數(shù)是hash=hash*31+*utf8Str++,hash變量初始為1,循環(huán)取得urf8Str的每一個字符進行運算,如下所示。[0044]while(*utf8Str!='\0')[0045]hash=hash*31+*utf8Str++;[0046]哈希函數(shù)的傳入?yún)?shù)為要查找的Java函數(shù)或Java變量的名字和簽名的連接字符串。循環(huán)對字符串的每一個字符進行運算,返回計算得到的哈希函數(shù)值。將哈希函數(shù)值對哈希表表長進行取模運算,即得到哈希單元的編號。[0047]所述步驟2中的內(nèi)建哈希表實際上是對在Dalvik虛擬機所定義的哈希表數(shù)據(jù)結(jié)構(gòu)HashTable的一個擴展,在原哈希表數(shù)據(jù)結(jié)構(gòu)HashTable中,每一個哈希單元包括兩個成員變量,hashValue和data,分別用來存儲哈希值和數(shù)據(jù)。但根據(jù)本優(yōu)化方案的需求,必須有一個數(shù)據(jù)已知的成員變量來處理沖突,所以對原HashTable數(shù)據(jù)結(jié)構(gòu)進行了擴展,向哈希單元中添加了一個新的字符指針成員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]所述哈希表的沖突處理為如果兩個或兩個以上方法的哈希函數(shù)值映射為同一個哈希值,則為發(fā)生了沖突。在向哈希表存儲數(shù)據(jù)時,首先判斷對應(yīng)的哈希值的單元的data成員是否為空,如果為空,則直接存入方法的指針,否則,發(fā)生了沖突,向前移動一個單元繼續(xù)判斷,直到找到data成員為空的哈希單元,存入數(shù)據(jù)。從哈希表取出數(shù)據(jù)時,為了避免沖突的影響,保證哈希函數(shù)值hashValue相等的同時,還要保證key字段一致。如果哈希函數(shù)值一致,而key不一致,說明產(chǎn)生了沖突,則向前移動一個哈希單元再次比較。比較key字段需要使用字符串比較函數(shù)strcmp,為了降低計算開銷,應(yīng)盡量縮短key的長度。令每一個類都有一個哈希表,而不是設(shè)置一個全局的哈希表,就是為了達到key字段盡量簡短的目的。[0062]所述步驟3中原系統(tǒng)函數(shù)指代的是原接口函數(shù)中負責具體查找操作的功能函數(shù)。當目標數(shù)據(jù)不在哈希表中,將會調(diào)用原系統(tǒng)函數(shù)查找獲取目標MethodID數(shù)據(jù)。其中對于接口函數(shù)GetMethodID,其原系統(tǒng)函數(shù)為dvmFindVirtualMethodHierByDescriptor函數(shù);對于接口與函數(shù)GetStaticMethodID,其原系統(tǒng)函數(shù)為dvmFindDirectMethodHierByDescriptor函數(shù)。[0063]將該技術(shù)技術(shù)方案引入到原接口函數(shù)適當位置后,將有效提高原接口函數(shù)的執(zhí)行效率,同時也不會對原接口功能有任何改變。優(yōu)化后的接口函數(shù)的完整工作流程如附圖2所示:[0064]步驟一:接口函數(shù)在執(zhí)行之初將首先接收傳入的參數(shù),主要包括主要包括目標方法所屬類的描述符、目標方法名以及簽名數(shù)據(jù),其中所屬類的描述符用于標識目標方法所屬的Java類、目標方法名和簽名數(shù)據(jù)作為目標方法的唯一標識。在目標方法所屬Java類的方法表中,虛擬機可以通過目標方法名和簽名數(shù)據(jù)即可找到目標方法的MethodID數(shù)據(jù)。[0065]步驟二:在正確接收入口參數(shù)后,接口函數(shù)將根據(jù)參數(shù)-所屬類的描述符,判斷虛擬機是否已加載該Java類,如果尚未加載該Java類,將調(diào)用相關(guān)的類加載函數(shù)完成該Java類的加載工作;否則,進入下一工作步驟。類加載工作的意義在于,虛擬機需要將目標Java類的數(shù)據(jù)讀入并解析,然后再其內(nèi)部的運行時環(huán)境中生成一個目標類的實例對象。隨后,虛擬機才可以通過該實例對象對該類的相關(guān)數(shù)據(jù)進行操作使用,而這一讀入解析的過程稱為類的加載。[0066]步驟三:若目標方法所屬的Java類已經(jīng)被正確加載,接口函數(shù)將根據(jù)另外兩個入口參數(shù)-目標方法名和簽名數(shù)據(jù),在內(nèi)建哈希表中查找目標方法的MethodID數(shù)據(jù),并將查找結(jié)果進行返回。內(nèi)建哈希表的定義在前面已經(jīng)敘述,再此不再贅述。[0067]步驟四:當接口函數(shù)完成了在內(nèi)建哈希表中查找目標數(shù)據(jù)的工作后,將對查找結(jié)果進行非空判斷:若該結(jié)果非空,則表示已經(jīng)查找到目標數(shù)據(jù),該數(shù)據(jù)將被接口函數(shù)返回,接口函數(shù)工作結(jié)束;否則表示內(nèi)建哈希表中尚未保存該目標數(shù)據(jù),接口函數(shù)將調(diào)用原系統(tǒng)函數(shù)在目標方法所屬Java類中的方法表中,對目標方法的MethodID數(shù)據(jù)進行常規(guī)的查找工作-即步驟五,并將查找結(jié)果進行返回。[0068]步驟五:常規(guī)的查找工作結(jié)束后,接口函數(shù)將對查找結(jié)果進行非空判斷,若查找結(jié)果非空,則表示查找到目標方法的MethodID數(shù)據(jù),該數(shù)據(jù)隨后將被插入到內(nèi)建哈希表中并將該數(shù)據(jù)作為接口函數(shù)的返回值進行返回,若虛擬機再次訪問該數(shù)據(jù)時,將從內(nèi)建哈希表中直接取出,而不用再調(diào)用原系統(tǒng)函數(shù)進行查找;若查找結(jié)果為空,接口函數(shù)將拋出異常并返回。[0069]本實施所基于的測試環(huán)境是Android4.0.4,其中Dalvik虛擬機的使用JNI本地接口函數(shù)GetMethodID和GetStaticMethodID(當函數(shù)為靜態(tài)函數(shù)時)來獲得函數(shù)的MethodID,上述接口函數(shù)定義位于Dalvik虛擬機源碼路徑:dalvik/vm/jn1.cpp。[0070]實施時,具體如附圖4所示,接口函數(shù)首先判斷目標方法的所屬類是否已被虛擬機加載,如是則跳過這一步,否則將調(diào)用dvmlnitClass(clazz)函數(shù)對該類進行加載并初始化。然后判斷內(nèi)建哈希表是否創(chuàng)建,如是則進行下一步操作,否則創(chuàng)建內(nèi)建哈希表。[0071]實施時,具體如附圖4所示,所述連接字符串name和sig,構(gòu)建key是指,將入口參數(shù)name變量(字符型數(shù)組,用于表示目標方法名)以及sig變量(字符型數(shù)組,用于表示簽名)進行字符串拼接并存入methodkey變量(字符型數(shù)組,用于表示目標方法名和簽名的字符串連接)。[0072]實施時,具體如附圖4所示,所述在哈希表中查找目標數(shù)據(jù),并返回ID是指,接口函數(shù)在得到methodkey變量后,將調(diào)用函數(shù)dvmComputeUtf8mHash并以methodkey變量作為參數(shù)計算對應(yīng)的哈希值并將結(jié)果保存在hashvalue變量中,隨后將調(diào)用函數(shù)dvmmHashTableLookup在內(nèi)建哈希表中查找目標數(shù)據(jù)。其函數(shù)功能描述如下:dvmmHashTabIeLookup(mHashTabIe^pHashTable,u4itemHash,char*key,HashCompareFunccmpFunc)實現(xiàn)哈希表的查找功能,參數(shù)cmpFunc為哈希比較函數(shù),這里為strcmp,用來比較key成員字段。根據(jù)計算得到的哈希值itemHash定位到指定的哈希單元,如果data成員非空,并且itemHash成員和key成員分別各自相等,那么就找到指定ID,可直接使用。[0073]實施時,具體如附圖4所示,在函數(shù)列表中查找目標數(shù)據(jù)是指,當dvmmHashTableLookup函數(shù)返回值為空時,接口函數(shù)將調(diào)用原系統(tǒng)函數(shù)在對應(yīng)的函數(shù)列表中查找目標數(shù)據(jù)。其中對于接口函數(shù)GetMethodID,其原統(tǒng)函數(shù)為dvmFindVirtualMethodHierByDescriptor函數(shù);對于接口與函數(shù)GetStaticMethodID,其原系統(tǒng)函數(shù)為dvmFindDirectMethodHierByDescriptor函數(shù)。[0074]實施時,具體如附圖4所示,判斷查找結(jié)果是否為空是指,判斷原系統(tǒng)函數(shù)的返回值是否為空。若為空,則表示目標方法不存在于當前Java類,系統(tǒng)將拋出異常并返回;若為非空,則表示正確找到目標方法數(shù)據(jù),該數(shù)據(jù)將做為接口函數(shù)的返回值。其中對于接口函數(shù)GetMethodID,本步驟用于判斷dvmFindVirtualMethodHierByDescriptor函數(shù)返回值是否為空;對于接口函數(shù)GetStaticMethodID,本步驟用于判斷dvmFindDirectMethodHierByDescriptor函數(shù)返回值是否為空。[0075]實施時,具體如附圖4所示,將結(jié)果插入哈希表是指,若dvmFindVirtualMethodHierByDescriptor函數(shù)或dvmFindDirectMethodHierByDescriptor函數(shù)的返回值非空時,接口函數(shù)將調(diào)用dvmmHashTabIeAdd函數(shù)將返回值插入內(nèi)建哈希表。[0076]在上述實施過程中所使用到的功能函數(shù)中,dvmmHashTabIeLookup以及dvmmHashTabIeAdd函數(shù)為本發(fā)明依據(jù)優(yōu)化需求自行開發(fā)的功能函數(shù),其余為Dalvik虛擬機原功能函數(shù)。[0077]dvmmHashTabIeLookup函數(shù)用于在內(nèi)建哈希表中匹配查找目標方法數(shù)據(jù)的FieldID,其函數(shù)代碼如下:[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函數(shù)用于將一個目標方法的相關(guān)數(shù)據(jù)信息(包括字段描述信息的哈希值、字段描述信息以及字段對應(yīng)的FieldID),其函數(shù)代碼如下:[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]本方案在實施過程表現(xiàn)出了較好優(yōu)化效果,下面是優(yōu)化后接口函數(shù)性能測試結(jié)果展示:[0150]本發(fā)明中所采用的測試用例主要用于測試GetMethodID、GetStaticMethodID兩個接口函數(shù)優(yōu)化前后的性能。測試用例在執(zhí)行過程中將頻繁調(diào)用GetMethodID或GetStaticMethodID函數(shù)獲取某一目標數(shù)據(jù),以此來模擬出大量冗余操作,用于考察采用優(yōu)化方案的接口函數(shù)是否可以有效地提高系統(tǒng)性能。[0151]由于接口函數(shù)獲取Java類中MethodID時需要遍歷訪問對應(yīng)的函數(shù)列表,列表的長度的大小對于查找效率有很大影響,因此通過增減Java類中函數(shù)數(shù)量,用以測試在不同的函數(shù)數(shù)量的情況下優(yōu)化前后的本地調(diào)用接口獲取MethodID時間變化,以達到全面衡量接口函數(shù)的優(yōu)化質(zhì)量。[0152]還需要指出的是:當接口函數(shù)在Java類的函數(shù)列表查找目標數(shù)據(jù)時,若目標數(shù)據(jù)在查找列表中位置相對靠前,那么接口函數(shù)所消耗時間就相對較短,反之則較長。因此為了減小目標數(shù)據(jù)在查找列表中位置的不同所引起的影響,測試用例要求對于查找列表中的每一個函數(shù),其被查找的次數(shù)相同,同時測試結(jié)果為查找各個函數(shù)平均查找時間。[0153](I)測試結(jié)果:[0154]基準測試程序的Java類包含有10個普通函數(shù)、10個靜態(tài)函數(shù),分別調(diào)用2個接口函數(shù)獲取Java類中每個MethodID,每個接口函數(shù)執(zhí)行30000次,運行測試程序50次,計算每個接口函數(shù)的平均耗時,實驗結(jié)果如下表所示,附圖7中時間單位為ms。附圖7展示了優(yōu)化之前和優(yōu)化之后各個接口函數(shù)的執(zhí)行時間,以及優(yōu)化之后相對于優(yōu)化之前的時間變化。[0155]由于接口函數(shù)在查找目標數(shù)據(jù)時,需要遍歷Java類的函數(shù)列表來查找目標Java類的函數(shù)列表,因此Java類的函數(shù)的數(shù)量直接影響了優(yōu)化前后查找方式的查找效率。為了進一步展示優(yōu)化效果,在基準測試程序的基礎(chǔ)上,改變Java類中的函數(shù)的數(shù)量并重復進行多組測試,以達到全面定量分析接口優(yōu)化后的性能情況。[0156]接口函數(shù)GetMethodID定量測試結(jié)果如附圖5所示,其中GetMethodID指代原接口函數(shù),GetMethodIDhs指代優(yōu)化后接口函數(shù)。[0157]接口函數(shù)GetStatiMethodID定量測試結(jié)果如附圖6所不,其中GetStatiMethodID指代原接口函數(shù),GetStaticMethodIDhs指代優(yōu)化后接口函數(shù)。[0158](2)結(jié)果分析:[0159]對于前面的基準測試用例,其測試數(shù)據(jù)如表I所示,原接口函數(shù)GetMethodID、GetStaticMethodID與改進優(yōu)化后的接口函數(shù)的執(zhí)行消耗時間差別較為明顯,改進優(yōu)化后的接口函數(shù)的加速比分別為1.37、1.35,改進優(yōu)化效果較好,性能較之前提高近35%。[0160]在定量分析測試階段中,從少到多逐漸增加測試用例中的函數(shù)的數(shù)量,得出接口函數(shù)執(zhí)行時間變化曲線,附圖5和附圖6分別為接口函數(shù)GetMethodID和GetStaticMethodID改進優(yōu)化之前和改進優(yōu)化之后的接口函數(shù)查找執(zhí)行時間隨Java類的函數(shù)數(shù)量變化對比曲線圖。如附圖5和附圖6所示,當Java類中函數(shù)數(shù)量在3個之內(nèi)時,改進之前的接口函數(shù)GetMethodID(GetStaticMethodID)和改進之后的接口函數(shù)GetMethodIDhs(GetStaticMethodIDhs)的查找執(zhí)行時間相差不多,而改進后接口函數(shù)GetMethodIDhs(GetStaticMethodIDhs)的執(zhí)行時間略快于改進前接口函數(shù)GetMethodID(GetStaticMethodID)ο當Java類中函數(shù)數(shù)量由3個開始增多時,接口函數(shù)查找MethodID的執(zhí)行時間開始增多,但是原接口GetMethodID(GetStaticMethodID)的執(zhí)行時間要比改進后接口函數(shù)GetMethodIDhs(GetStaticMethodIDhs)的執(zhí)行時間增長得更快,改進優(yōu)化后的接口函數(shù)的加速比越來越大,優(yōu)化性能越來越大,當Java類包含8個函數(shù)時,加速比平均為1.31,當Java類中函數(shù)數(shù)量為14時,加速比達到1.53,可見改進優(yōu)化后的接口函數(shù)GetMethodIDhs和GetStaticMethodIDhs的優(yōu)化性能隨著Java類中函數(shù)數(shù)量的增多而增大。【權(quán)利要求】1.一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:(1)在目標接口函數(shù)的適當位置植入數(shù)據(jù)索引機制;(2)獲取目標數(shù)據(jù)的標識常量并調(diào)用哈希函數(shù)計算標識常量的哈希值;(3)根據(jù)哈希值在內(nèi)建哈希表查找目標表項,如存在則直接返回目標數(shù)據(jù)地址,否則實施步驟(4);(4)根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù),如找到則將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表中并正確返回;否則拋出異常并返回。2.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(I)中目標接口函數(shù)適當位置是指:對于GetMethodID函數(shù),適當位置為GetMethodID函數(shù)調(diào)用dvmFindVirtualMethodHierByDescriptor函數(shù)對目標MethodID查找之前,在此處引入一個數(shù)據(jù)索引機制;對于GetStaticMethodID函數(shù),適當位置為GetStaticMethodID函數(shù)調(diào)用dvmFindDirectMethodHierByDescriptor函數(shù)對目標MethodID查找之前。3.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(2)中目標數(shù)據(jù)的標識常量是指目標方法所屬類的描述符、目標方法名以及簽名數(shù)據(jù);其中計算標識常量的哈希值是指,調(diào)用Dalvik虛擬機提供的哈希函數(shù)計算目標數(shù)據(jù)標識常量字符串哈希值。4.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(3)中內(nèi)建哈希表是指,一個哈希表數(shù)據(jù)結(jié)構(gòu)HashTable,每一個哈希單元包括三個成員變量,分別用于存儲標識常量的哈希值、標識常量的字符拼接以及目標方法的MethodID。5.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(3)中根據(jù)該哈希值在內(nèi)建哈希表查找目標表項是指,根據(jù)步驟21)中生成的哈希值在內(nèi)建哈希表中查找匹配目標表項并返回目標方法的MethodID。6.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(4)中根據(jù)目標數(shù)據(jù)常量標識,調(diào)用原系統(tǒng)函數(shù)查找目標數(shù)據(jù)是指,當步驟(3)的返回值為空時,接口函數(shù)將會調(diào)用原系統(tǒng)函數(shù)并根據(jù)目標數(shù)據(jù)常量標識查找目標方法的MethodID,其中對于接口函數(shù)GetMethodID,原系統(tǒng)函數(shù)為dvmFindVirtualMethodHierByDescriptor函數(shù);對于接口與函數(shù)GetStaticMethodID,原系統(tǒng)函數(shù)為dvmFindDirectMethodHierByDescriptor函數(shù)。7.根據(jù)權(quán)利要求1所述的一種基于Dalvik虛擬機JNI機制中接口函數(shù)GetMethodID和GetStaticMethodID性能優(yōu)化方法,其特征在于:所述步驟(4)將目標數(shù)據(jù)以及其標識常量的哈希值插入內(nèi)建哈希表是指,當步驟(3)返回值為空時,接口函數(shù)GetMethodID或GetStaticMethodID通過原系統(tǒng)函數(shù)查找到目標方法的MethodID數(shù)據(jù)后,將MethodID數(shù)據(jù)和與之對應(yīng)的常量標識以及常量標識的哈希值插入內(nèi)建哈希表中。【文檔編號】G06F9/455GK104035809SQ201410177666【公開日】2014年9月10日申請日期:2014年4月29日優(yōu)先權(quán)日:2014年4月29日【發(fā)明者】吳艷霞,張國印,謝東良,許圣明,王彥彰申請人:哈爾濱工程大學