日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jvm 方法内联_方法内联在JVM中有多积极?

發(fā)布時(shí)間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jvm 方法内联_方法内联在JVM中有多积极? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

jvm 方法內(nèi)聯(lián)

在IntelliJ IDEA中使用Ctrl + Alt + M 提取方法 。 Ctrl + Alt + M。 這就像選擇一段代碼并按此組合一樣簡單。 Eclipse也有它 。 我討厭冗長的方法。 對(duì)于我來說,聞起來太久了:

public void processOnEndOfDay(Contract c) {if (DateUtils.addDays(c.getCreated(), 7).before(new Date())) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if(sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);} }

首先,它具有不可讀的條件。 無關(guān)緊要的實(shí)現(xiàn)方式,重要的是做什么。 因此,讓我們首先提取它:

public void processOnEndOfDay(Contract c) {if (isOutdated(c)) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if(sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);} }private boolean isOutdated(Contract c) {return DateUtils.addDays(c.getCreated(), 7).before(new Date()); }

顯然,此方法實(shí)際上并不屬于這里( F6 –移動(dòng)實(shí)例方法):

public void processOnEndOfDay(Contract c) {if (c.isOutdated()) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c);} else {if(sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);} }

注意到不同了嗎? 我的IDE使isOutdated()是Contract的實(shí)例方法,聽起來isOutdated() 。 但是我還是不開心。 這種方法發(fā)生了太多的事情。 一個(gè)分支執(zhí)行一些與業(yè)務(wù)相關(guān)的priorityHandling() ,一些系統(tǒng)通知和日志記錄。 其他分支執(zhí)行條件通知和日志記錄。 首先,讓我們將處理過時(shí)的合同轉(zhuǎn)移到單獨(dú)的方法中:

public void processOnEndOfDay(Contract c) {if (c.isOutdated()) {handleOutdated(c);} else {if(sendNotifications) {notifyPending(c);}log.debug("Pending {}", c);} }private void handleOutdated(Contract c) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c); }

也許有人說這足夠了,但是我看到分支之間驚人的不對(duì)稱性。 handleOutdated()是非常高級(jí)的,而發(fā)送else分支是技術(shù)性的。 軟件應(yīng)易于閱讀,因此請勿將不同級(jí)別的抽象彼此混用。 現(xiàn)在我很高興:

public void processOnEndOfDay(Contract c) {if (c.isOutdated()) {handleOutdated(c);} else {stillPending(c);} }private void handleOutdated(Contract c) {priorityHandling(c, OUTDATED_FEE);notifyOutdated(c);log.info("Outdated: {}", c); }private void stillPending(Contract c) {if(sendNotifications) {notifyPending(c);}log.debug("Pending {}", c); }

這個(gè)例子有些人為,但實(shí)際上我想證明一些不同的東西。 這些天并不經(jīng)常出現(xiàn),但是仍然有開發(fā)人員擔(dān)心提取方法會(huì)認(rèn)為它在運(yùn)行時(shí)速度較慢。 他們無法理解JVM是一款很棒的軟件(它可能遠(yuǎn)遠(yuǎn)超過Java語言),它內(nèi)置了許多真正令人驚嘆的運(yùn)行時(shí)優(yōu)化。 首先,較短的方法更容易推理。 流動(dòng)更明顯,范圍更短,副作用更明顯。 使用長方法,JVM可能會(huì)簡單地放棄。 第二個(gè)原因更為重要:

方法內(nèi)聯(lián)

如果JVM發(fā)現(xiàn)一遍又一遍執(zhí)行的小方法,它將簡單地用該方法的主體替換該方法的每次調(diào)用。 以此為例:

private int add4(int x1, int x2, int x3, int x4) {return add2(x1, x2) + add2(x3, x4); }private int add2(int x1, int x2) {return x1 + x2; }

您可能幾乎可以確定,一段時(shí)間后JVM將擺脫add2()并將代碼轉(zhuǎn)換為:

private int add4(int x1, int x2, int x3, int x4) {return x1 + x2 + x3 + x4; }

重要說明是它是JVM,而不是編譯器。 生成字節(jié)碼時(shí), javac非常保守,并將所有工作都留給了JVM。 這個(gè)設(shè)計(jì)決定非常出色:

  • JVM對(duì)目標(biāo)環(huán)境,CPU,內(nèi)存,體系結(jié)構(gòu)了解更多,并且可以更積極地進(jìn)行優(yōu)化
  • JVM可以發(fā)現(xiàn)代碼的運(yùn)行時(shí)特征,例如,哪些方法最常執(zhí)行,哪些虛擬方法只有一種實(shí)現(xiàn)等。
  • 使用舊Java編譯的.class將在較新的JVM上運(yùn)行得更快。 您很可能會(huì)更新Java,然后重新編譯源代碼。

讓我們對(duì)所有這些假設(shè)進(jìn)行測試。 我寫了一個(gè)小程序,標(biāo)題為“ 有史以來最糟糕的分而治之原則 。 add128()接受128個(gè)參數(shù)(!),并調(diào)用add64()兩次–參數(shù)的前一半和后一半。 add64()類似于,只是它兩次調(diào)用add32() 。 我想您會(huì)明白的,最后我們要使用add2()來完成繁重的工作。 一些數(shù)字被截?cái)嘁悦庖鹉淖⒁?:

public class ConcreteAdder {public int add128(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128) {return add64(x1, x2, x3, x4, ... more ..., x63, x64) +add64(x65, x66, x67, x68, ... more ..., x127, x128);}private int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64) {return add32(x1, x2, x3, x4, ... more ..., x31, x32) +add32(x33, x34, x35, x36, ... more ..., x63, x64);}private int add32(int x1, int x2, int x3, int x4, ... more ..., int x31, int x32) {return add16(x1, x2, x3, x4, ... more ..., x15, x16) +add16(x17, x18, x19, x20, ... more ..., x31, x32);}private int add16(int x1, int x2, int x3, int x4, ... more ..., int x15, int x16) {return add8(x1, x2, x3, x4, x5, x6, x7, x8) + add8(x9, x10, x11, x12, x13, x14, x15, x16);}private int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8) {return add4(x1, x2, x3, x4) + add4(x5, x6, x7, x8);}private int add4(int x1, int x2, int x3, int x4) {return add2(x1, x2) + add2(x3, x4);}private int add2(int x1, int x2) {return x1 + x2;}}

不難看出,通過調(diào)用add128()我們總共進(jìn)行了127個(gè)方法調(diào)用。 很多。 僅供參考,這里是一個(gè)簡單的實(shí)現(xiàn) :

public class InlineAdder {public int add128n(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128) {return x1 + x2 + x3 + x4 + ... more ... + x127 + x128;}

最后,我還提供了一個(gè)使用abstract方法和繼承的實(shí)現(xiàn)。 127個(gè)虛擬呼叫非常昂貴。 這些方法需要?jiǎng)討B(tài)調(diào)度 ,因此要求更高,因?yàn)樗鼈儫o法內(nèi)聯(lián)。 不能嗎

public abstract class Adder {public abstract int add128(int x1, int x2, int x3, int x4, ... more ..., int x127, int x128);public abstract int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64);public abstract int add32(int x1, int x2, int x3, int x4, ... more ..., int x31, int x32);public abstract int add16(int x1, int x2, int x3, int x4, ... more ..., int x15, int x16);public abstract int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8);public abstract int add4(int x1, int x2, int x3, int x4);public abstract int add2(int x1, int x2); }

和一個(gè)實(shí)現(xiàn):

public class VirtualAdder extends Adder {@Overridepublic int add128(int x1, int x2, int x3, int x4, ... more ..., int x128) {return add64(x1, x2, x3, x4, ... more ..., x63, x64) +add64(x65, x66, x67, x68, ... more ..., x127, x128);}@Overridepublic int add64(int x1, int x2, int x3, int x4, ... more ..., int x63, int x64) {return add32(x1, x2, x3, x4, ... more ..., x31, x32) +add32(x33, x34, x35, x36, ... more ..., x63, x64);}@Overridepublic int add32(int x1, int x2, int x3, int x4, ... more ..., int x32) {return add16(x1, x2, x3, x4, ... more ..., x15, x16) +add16(x17, x18, x19, x20, ... more ..., x31, x32);}@Overridepublic int add16(int x1, int x2, int x3, int x4, ... more ..., int x16) {return add8(x1, x2, x3, x4, x5, x6, x7, x8) + add8(x9, x10, x11, x12, x13, x14, x15, x16);}@Overridepublic int add8(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8) {return add4(x1, x2, x3, x4) + add4(x5, x6, x7, x8);}@Overridepublic int add4(int x1, int x2, int x3, int x4) {return add2(x1, x2) + add2(x3, x4);}@Overridepublic int add2(int x1, int x2) {return x1 + x2;}}

在有關(guān)@Cacheable開銷的文章發(fā)表后,受到一些有趣的讀者意見的鼓勵(lì),我編寫了一個(gè)快速基準(zhǔn)測試,以比較過度提取的ConcreteAdder和VirtualAdder開銷(以查看虛擬調(diào)用開銷)。 結(jié)果出乎意料,有些模棱兩可。 我在兩臺(tái)機(jī)器(藍(lán)色和紅色)和相同的軟件上運(yùn)行相同的基準(zhǔn)測試,但是第二臺(tái)具有更多內(nèi)核,并且是64位:

詳細(xì)環(huán)境:

事實(shí)證明,在一臺(tái)速度較慢的計(jì)算機(jī)上, JVM決定內(nèi)聯(lián)所有內(nèi)容。 不僅簡單的private通話,而且虛擬的一次通話。 那怎么可能 很好,JVM發(fā)現(xiàn)Adder只有一個(gè)子類,因此每個(gè)abstract方法只有一個(gè)可能的版本。 如果在運(yùn)行時(shí)加載另一個(gè)子類(或什至更多子類),則可能會(huì)看到性能下降,因?yàn)椴辉倏赡苓M(jìn)行內(nèi)聯(lián)。 但是拋開細(xì)節(jié),在此基準(zhǔn)測試方法中調(diào)用并不便宜,實(shí)際上是免費(fèi)的 ! 方法調(diào)用(具有極大的文檔價(jià)值,提高了可讀性)僅存在于源代碼和字節(jié)碼中。 在運(yùn)行時(shí),它們被完全消除(內(nèi)聯(lián))。

我不太了解第二個(gè)基準(zhǔn)。 看起來機(jī)器B的運(yùn)行速度確實(shí)更快,但實(shí)際上運(yùn)行參考SingleMethodCall基準(zhǔn)測試的速度更快,但是其他機(jī)器甚至比A都慢。 也許它決定推遲內(nèi)聯(lián)? 差異是顯著的,但并不是那么大。 同樣,就像優(yōu)化堆棧跟蹤生成一樣,如果您開始通過手動(dòng)內(nèi)聯(lián)方法來優(yōu)化代碼,從而使它們變得更長和復(fù)雜,那么您正在解決錯(cuò)誤的問題。

該基準(zhǔn)可在GitHub上獲得 ,以及文章來源 。 我鼓勵(lì)您在設(shè)置中運(yùn)行它。 此外,每個(gè)拉取請求都是自動(dòng)在Travis上構(gòu)建的,因此您可以在同一環(huán)境下輕松比較結(jié)果。

參考: JVM中方法內(nèi)聯(lián)的攻擊性如何? 來自我們的JCG合作伙伴 Tomasz Nurkiewicz,來自Java和鄰里博客。

翻譯自: https://www.javacodegeeks.com/2013/02/how-aggressive-is-method-inlining-in-jvm.html

jvm 方法內(nèi)聯(lián)

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的jvm 方法内联_方法内联在JVM中有多积极?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。