




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
及方法給了應(yīng)用程序。在運(yùn)行過(guò)程中,每一條invokedynamic指令將一個(gè)調(diào)invokedynamic指令時(shí),Java(BootStrapMethod),invokedynamic指令中。在之后的運(yùn)行過(guò)程中,Java虛擬機(jī)則會(huì)直接調(diào)用綁定的調(diào)用點(diǎn)所的方法句p夠的方法句柄的類(lèi)型。1import2classHorsepublicvoidrace() 78classDeerpublicvoidrace() 13//javac//javapublicclassCircuitpublicstaticvoidstartRace(Objectobj)//aload//invokedynamic publicstaticvoidmain(String[]args)startRace(new//startRace(new 33
publicstaticCallSitebootstrap(MethodHandles.Lookupl,Stringname,MethodTypecallMethodHandlemh=l.findVirtual(Horse.class,name,MethodType.methodType(void.classreturnnewConstantCallSite(mh.asType(callSiteType));}并且返回一個(gè)至Horse.race方法的ConstantCallSite。這里的ConstantCallSite是一種不可以更改對(duì)象的調(diào)用點(diǎn)。除此之外,Java類(lèi)庫(kù)還提供多種可以更改對(duì)象的調(diào)用點(diǎn),比如MutableCallSite和VolatileCallSite。volatile由于Java暫不支持直接生成invokedynamic指令[1] 字節(jié)碼工具ASM來(lái)實(shí)現(xiàn)這一目的importjava.io.IOExcepimporjaa.anginokimportjava.no45import6//javac-cp/path/to/asm-all-6.0_BETA.jar:.//java-cp/path/to/asm-all-6.0_BETA.jar:.//javapublicclassASMHelperimplementsOpcodes privatestaticclassMyMethodVisitorextendsMethodVisitorprivatestaticfinalStringBOOTSTRAP_CLASS_NAME=Circuit.class.getName().reprivatestaticfinalStringBOOTSTRAP_METHOD_NAME=bootstrapprivatestaticfinalStringBOOTSTRAP_METHOD_DESC=.methodType(CallSite.class,MethodHandles.Lookup.class,String.class, privatestaticfinalStringTARGET_METHOD_NAME=race privatestaticfinalStringTARGET_METHOD_DESC=(Ljava/lang/Object;)V publicfinalMethodVisitor publicMyMethodVisitor(intapi,MethodVisitormv)this.mv=}publicvoidvisitCode()mv.visitVarInsn(ALOAD,Handleh=newHandle(H_INVOKESTATIC,BOOTSTRAP_CLASS_NAME,mv.visitInvokeDynamicInsn(TARGET_METHOD_NAME,TARGET_METHOD_DESC,mv.visitMaxs(1,}}publicstaticvoidmain(String[]args)throwsIOExceptionClassReadercr=newClassWritercw=new ClassVisitorcv=newClassVisitor(ASM6,cw)publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdescriptor,String[]exceptions)MethodVisitorvisitor=super.visitMethod(access,name,descriptor,if("startRace".equals(name))returnnewMyMethodVisitor(ASM6,}return}cr.accept(cv,Files.write(Paths.get("Circuit.class"),}} 下Circuit類(lèi)1staticvoid20:31:invokedynamic#80,0//46:如果你足夠細(xì)心的話(huà),你會(huì)發(fā)現(xiàn)該指令所調(diào)用的賽跑方法的描述符,和Horse.ae者ae方法的描述符并不一致。這是因?yàn)閚vonamic指令最終調(diào)用的是方法句柄,而方法句柄會(huì)將調(diào)用者當(dāng)成第一個(gè)參數(shù)。因此,剛剛提到的那兩個(gè)方法恰恰符合這個(gè)描述符所對(duì)應(yīng)的方法句柄類(lèi)型。到目前為止,我們已經(jīng)可以通過(guò)invokedynamic調(diào)用Horse.race方法了。為了支持調(diào)用任意類(lèi)的race方法,我實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的單態(tài)內(nèi)聯(lián)緩存。如果調(diào)用者的類(lèi)型命中緩存中的1//需要更改ASMHelper.MyMethodVisitor中的2import34publicclassMonomorphicInlineCache5privatefinalMethodHandles.LookupprivatefinalString8publicMonomorphicInlineCache(MethodHandles.Lookuplookup,Stringname)this.lookup== privateClass<?>cachedClass=privateMethodHandlemh=publicvoidinvoke(Objectreceiver)throwsThrowableif(cachedClass!=receiver.getClass())cachedClass=mh=lookup.findVirtual(cachedClass,name, publicstaticCallSitebootstrap(MethodHandles.Lookupl,Stringname,MethodTypeMonomorphicInlineCacheic=newMonomorphicInlineCache(l,MethodHandlemh=l.findVirtual(MonomorphicInlineCache.class,"invoke",returnnew 30不過(guò),這正是mc的目的,也就是將調(diào)用點(diǎn)與目標(biāo)方法的交由應(yīng)用程序來(lái)做,并且依賴(lài)于應(yīng)用程序?qū)δ繕?biāo)方法進(jìn)行驗(yàn)證。所以,如果應(yīng)用程序?qū)①惻芊椒ㄖ镣米拥乃X(jué)方法,那也只能怪應(yīng)用程序自己了。Java8的Lambda在Java8中,Lambdainvokedynamic具體來(lái)說(shuō),Java編譯器利用invokedynamic的函數(shù)式接口指的是僅包括一個(gè)非default接口方法的接口,一般通過(guò)@FunctionalInterface注解。不過(guò)就算是沒(méi)有使用該注解,Java編譯器也會(huì)將符合條件的intx=IntStream.of(1,2,3).map(i->i*2)ap(i>i* 上面這段代碼會(huì)對(duì)IntStream中的元素進(jìn)行兩次映射。我們知道,映射方法map所接收的參數(shù)是IntUnaryOperator(這是一個(gè)函數(shù)式接口)。也就是說(shuō),在運(yùn)行過(guò)程中我們需要將i->i2和i->ix這兩個(gè)Lambda表達(dá)式轉(zhuǎn)化成IntUnaryOperator的實(shí)例。這個(gè)轉(zhuǎn)化過(guò)程便是由invokedynamic來(lái)實(shí)現(xiàn)的。在編譯過(guò)程中,Java編譯器會(huì)對(duì)dadr)LambdaLambda數(shù),還包含它所捕獲的變量。(注:方法,如e,則不會(huì)生成生成額外的方在上面那個(gè)例子中,第一個(gè)LambdaLambda(i->i*x)xLambda //i->i*2staticint3456789//i-i*staticintlambda$1(int,第一次執(zhí)行invokedynamic指令時(shí),它所對(duì)應(yīng)的啟動(dòng)方通過(guò)ASM來(lái)生成一個(gè)適配器IntUnaryOperator。啟動(dòng)方法的返回值是一個(gè)ConstantCallSite,其對(duì)象為一個(gè)返回根據(jù)Lambda表達(dá)式是否捕獲其他變量,啟動(dòng)方法生成的適配器類(lèi)以及所的方法句柄LambdaLambdainvokedynamic另外,為了保證Lambda表達(dá)式的線程安全,我們無(wú)法共享同一個(gè)適配器類(lèi)的實(shí)例。因此,在每次執(zhí)行invokedynamic指令時(shí),所調(diào)用的方法句柄都需要新建一個(gè)適配器類(lèi)實(shí)例。你可以通過(guò)虛擬機(jī)參數(shù)-Dernal.lambda.dumpClasses=/DUMP/PATH導(dǎo)出這些具體的適配器類(lèi)。這里我導(dǎo)出了上面這個(gè)例子中兩個(gè)Lambda表達(dá)式對(duì)應(yīng)的適配器//i->i*2finalclassLambdaTest$$Lambda$1implementsIntUnaryOperatorprivate0:1:invokespecial4:8publicint0:1:invokestatic4:14//i->i*xfinalclassLambdaTest$$Lambda$2implementsIntUnaryOperatorprivatefinalintprivate0:1:invokespecial4:5:6:putfield9:privatestaticjava.util.function.IntUnaryOperator0:new3:4:5:invokespecial8:publicint0:1:getfield4:5:invokestatic8:44Lambdaget$Lambdainvokedynamic指令時(shí),都會(huì)調(diào)用至這個(gè)方法中,并構(gòu)造一個(gè)新的適配器類(lèi)實(shí)例。Lambdav6import34publicclassTest5publicstaticvoidtarget(inti){67publicstaticvoidmain(String[]args)throwsException8longcurrent=9for(inti=1;i<=2_000_000_000;i++)if(i%100_000_000==0)longtemp=System.out.println(temp-current=}((IntConsumer)j->//((IntConsumer)}}}LambdainvokedynamicIntConsumer.acceptLambda另一方面,對(duì)IntConsumer.accept方法的調(diào)用實(shí)則是對(duì)適配器類(lèi)的accept方法的調(diào)用。如果你查看了accept方法對(duì)應(yīng)的字節(jié)碼的話(huà),你會(huì)發(fā)現(xiàn)它僅包含一個(gè)方法調(diào)用,調(diào)用至JavaLambdaLambdaTest.target。將這幾個(gè)方法調(diào)用內(nèi)聯(lián)進(jìn)來(lái)之后,原本對(duì)accept方法的調(diào)用則會(huì)被優(yōu)化為空操作。下面我將之前的代碼更改為帶捕獲變量的v7版本。理論上,每次調(diào)用invokedynamic指令,Javav7import3publicclassTestpublicstaticvoidtarget(inti){6publicstaticvoidmain(String[]args)throwsExceptionintx=9longcurrent=for(inti=1;i<=2_000_000_000;i++) if(i%100_000_000==0)longtemp=System.out.println(temp-current= ((IntConsumer)j->Test.target(x+ 21XX:-DoEscapeysis來(lái)關(guān)閉逃逸分析。果然,這時(shí)候測(cè)得的值約為直接調(diào)用的2.5倍。兩件事:invokedynamic指令所執(zhí)行的方法句柄能夠內(nèi)聯(lián),和接下來(lái)的對(duì)accept方法的適配器類(lèi)實(shí)例。所以,我們應(yīng)當(dāng)盡量使用非捕獲的Lambda表達(dá)式。invokedynamic指令以及Lambdaymaic指令出調(diào)的概并且用該點(diǎn)所的方柄。一amicJava虛擬機(jī)將執(zhí)行它所對(duì)應(yīng)的啟動(dòng)方法,生成并且綁定一個(gè)調(diào)用點(diǎn)。之后如果再次執(zhí)行該指令,Java虛擬機(jī)則直接調(diào)用已經(jīng)綁定了的調(diào)用點(diǎn)所鏈接的方法。對(duì)于沒(méi)有捕獲其他變量的Lambda表達(dá)式,該invokedynamic指令始終返回同一個(gè)適配器類(lèi)的實(shí)例。對(duì)于捕獲了其他變量的Lambda表達(dá)式,每次執(zhí)行invokedynamic指令將不管是捕獲型的還是未捕獲型的Lambda表達(dá)式,它們的性能上限皆可以達(dá)到直接調(diào)用的性能。其中,捕獲型Lambda表達(dá)式借助了即時(shí)編譯器中的逃逸分析,來(lái)避免實(shí)際的新建在上一篇的課后實(shí)踐中,你應(yīng)該測(cè)過(guò)這一段代碼的性能開(kāi)銷(xiāo)了。我這邊測(cè)得的結(jié)果約為直接5v8importimportimport5publicclassTestpublicstaticvoidtarget(inti){8925
publicstaticvoidmain(String[]args)throws{MethodHandles.Lookupl=MethodHandles.lookup();MethodTypet=MethodType.methodType(void.class,int.class);MethodHandlemh=l.findStatic(Test.class,"target",t);longcurrent=System.currentTimeMillis();for(inti=1;i<=2_000_000_000;i++){if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}實(shí)際上,它與使用Lambda表達(dá)式或者方法的差別在于,即時(shí)編譯器無(wú)法將該方法句法便是將其賦值給final的靜態(tài)變量,如下面的v9v9importimportimport5publicclassTestpublicstaticvoidtarget(inti){8staticfinalMethodHandlestatictryMethodHandles.Lookupl=MethodTypet=MethodType.methodType(void.class,mh=l.findStatic(Test.class,"target",}catch(Throwablee)thrownew publicstaticvoidmain(String[]args)throwsThrowablelongcurrent=32
for(inti=1;i<=2_000_000_000;{if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}v10v11//v10import34publicclassTest publicstaticvoidtarget(inti) 7 publicstaticclassMyCallSite9 publicfinalMethodHandlepublicMyCallSite()mh= privatestaticMethodHandlefindTarget()tryMethodHandles.Lookupl=MethodTypet=MethodType.methodType(void.class,returnl.findStatic(Test.class,"target",}catch(Throwablee)thrownew 41
privatestaticfinalMyCallSitemyCallSite=newpublicstaticvoidmain(String[]args)throws{longcurrent=System.currentTimeMillis();for(inti=1;i<=2_000_000_000;i++){if(i%100_000_000==0)longtemp=System.currentTimeMillis();System.out.println(temp-current);current=temp;}}}//v11importpublicclassTestpublicstaticvoidtarget(inti)} publicstaticclassMyCallSiteextendsConstantCallSitepublicMyCallSite() privatestaticMethodHandlefindTarget()tryMethodHandles.Lookupl=MethodTypet=MethodType.met
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 浙江省蒼南縣重點(diǎn)名校2024-2025學(xué)年初三下語(yǔ)文試題第四次月考試卷解答含解析
- 江西中醫(yī)藥大學(xué)《建筑工程虛擬顯示技術(shù)》2023-2024學(xué)年第一學(xué)期期末試卷
- 蒙自縣2025屆三下數(shù)學(xué)期末綜合測(cè)試模擬試題含解析
- 天津仁愛(ài)學(xué)院《英語(yǔ)3》2023-2024學(xué)年第二學(xué)期期末試卷
- 河南省三門(mén)峽盧氏縣聯(lián)考2024-2025學(xué)年初三聯(lián)合模擬考試生物試題含解析
- 綏化學(xué)院《材料研究及分析方法》2023-2024學(xué)年第二學(xué)期期末試卷
- 黃金卷市級(jí)名校2025屆初三3月開(kāi)學(xué)考試英語(yǔ)試題文試卷含答案
- 洛陽(yáng)文化旅游職業(yè)學(xué)院《輿情大數(shù)據(jù)分析》2023-2024學(xué)年第二學(xué)期期末試卷
- 上海第二工業(yè)大學(xué)《西醫(yī)基礎(chǔ)概論》2023-2024學(xué)年第一學(xué)期期末試卷
- 深圳北理莫斯科大學(xué)《大數(shù)據(jù)分析與應(yīng)用綜合實(shí)驗(yàn)(一)》2023-2024學(xué)年第二學(xué)期期末試卷
- 登錄用戶(hù)協(xié)議
- 有絲分裂說(shuō)課
- 基于PLC洗車(chē)系統(tǒng)設(shè)計(jì)
- 低壓綜合配電箱二次配線工藝守則
- 中國(guó)動(dòng)畫(huà)的發(fā)展中國(guó)動(dòng)畫(huà)發(fā)展史課件
- 2023年中央企業(yè)全面風(fēng)險(xiǎn)管理報(bào)告(模本)
- 浙江省紹興市2023年中考英語(yǔ)真題(附答案)
- 龍虎斗(2017廣東廣州中考記敘文閱讀試題含答案)
- 錯(cuò)合畸形的預(yù)防與早期矯治-錯(cuò)合畸形的早期矯治(口腔正畸學(xué)課件)
- 地下鐵道-中南大學(xué)中國(guó)大學(xué)mooc課后章節(jié)答案期末考試題庫(kù)2023年
- 廢品站勞務(wù)合同范本
評(píng)論
0/150
提交評(píng)論