第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

JDK 中的非常規(guī)代碼 - 用于未知原因的特定構造

JDK 中的非常規(guī)代碼 - 用于未知原因的特定構造

慕萊塢森 2023-06-08 17:27:18
我正在查看 JDK(JDK 12,但它也適用于舊版本)代碼并發(fā)現(xiàn)了一些奇怪的結構,我不明白為什么要使用它們。讓我們舉個例子Map.computeIfPresent,因為它很簡單:default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {    Object oldValue;    if ((oldValue = this.get(key)) != null) {        V newValue = remappingFunction.apply(key, oldValue);        if (newValue != null) {            this.put(key, newValue);            return newValue;        } else {            this.remove(key);            return null;        }    } else {        return null;    }}這個結構if ((oldValue = this.get(key)) != null)讓我很吃驚。我知道這是可能的,因為它沒什么特別的,但在正常的生產代碼中我會認為它是一種代碼味道。為什么不直接寫成正常的方式(Object oldValue = this.get(key))?一定是一些離合器優(yōu)化,這就是我的想法。寫了一個較小的版本來檢查字節(jié)碼:int computeIfPresent(int key) {  Integer oldValue;  if ((oldValue = get(key)) != null) {    return oldValue;  } else {    return 2;  }}字節(jié)碼輸出:int computeIfPresent(int);  Code:     0: aload_0     1: iload_1     2: invokevirtual #2                  // Method get:(I)Ljava/lang/Integer;     5: dup     6: astore_2     7: ifnull        15    10: aload_2    11: invokevirtual #3                  // Method java/lang/Integer.intValue:()I    14: ireturn    15: iconst_2    16: ireturn具有經典變量初始化的“普通”版本的字節(jié)碼:int computeIfPresent(int);  Code:     0: aload_0     1: iload_1     2: invokevirtual #2                  // Method get:(I)Ljava/lang/Integer;     5: astore_2     6: aload_2     7: ifnull        15    10: aload_2    11: invokevirtual #3                  // Method java/lang/Integer.intValue:()I    14: ireturn    15: iconst_2    16: ireturn唯一的區(qū)別是dup + astore_2vs。astore_2 + aload_2我什至懷疑第一個“離合器優(yōu)化”版本更糟,因為dup它被使用并且堆棧無緣無故地更大。也許我的例子太簡單了,優(yōu)化在更復雜的上下文中擴展了很多。這是一個簡單的例子,絕對不是 JDK 代碼中的一個例子——打開HashMap.java,有很多這樣的片段,有時在同一行有多個:if ((first = tab[i = (n - 1) & hash]) != null)盡管它真的很簡單,但由于這些結構,我不得不停下來想一想這段代碼實際上做了什么。使用這些結構背后的真正原因是什么?我敢肯定這不僅僅是糟糕的代碼。在我看來,代碼質量受到很大影響,因此收益一定是可觀的。或者只是規(guī)則leave small optimizations to JIT不適用于 JDK,因為它必須盡可能多地壓縮性能?或者這只是規(guī)則的極端initialize variables as late as possible?:)
查看完整描述

1 回答

?
慕哥9229398

TA貢獻1877條經驗 獲得超6個贊

您的問題的答案在于 JVM 規(guī)范,特別是您指出的不同之處:指令dup(JVMS §6.5.dup)。從那些文檔:

復制操作數(shù)棧頂部的值并將復制的值壓入操作數(shù)棧。

查看操作數(shù)堆棧文檔(JVMS §2.6.2,重點添加):

少量 Java 虛擬機指令(dup指令 (§dup) 和swap(§swap))作為原始值在運行時數(shù)據(jù)區(qū)域上運行,而不考慮它們的特定類型;這些指令的定義方式使其不能用于修改或分解單個值。這些對操作數(shù)堆棧操作的限制是通過類文件驗證(§4.10)強制執(zhí)行的。

再深入一層,查看類驗證部分(JVMS §4.10,重點添加):

鏈接時驗證增強了運行時解釋器的性能。可以消除在運行時為每條解釋指令驗證約束而必須執(zhí)行的昂貴檢查。Java 虛擬機可以假定這些檢查已經執(zhí)行。

這表明這些限制是在鏈接時驗證的,也就是 JVM 加載您的類文件時。所以回答你的問題:

使用這些結構背后的真正原因是什么?

讓我們剖析一下指令在每種情況下的作用:

在第一種情況下(使用說明dup):

  1. invokevirtual將結果存儲在操作數(shù)棧的頂部

  2. dup重復所以現(xiàn)在在堆棧頂部有兩個結果副本

  3. astore_2將其存儲到局部變量 #2 中,該變量從操作數(shù)堆棧中彈出一個引用

  4. ifnull檢查操作數(shù)棧的頂部是否為空,如果是,則轉到指令 15,否則繼續(xù)(我們假設它不為空)

  5. aload_2將局部變量#2 推入操作數(shù)棧的頂部

  6. invokevirtual在操作數(shù)棧的頂部調用一個方法,彈出它,然后壓入結果

  7. ireturn從操作數(shù)棧彈出頂部值并返回它

在第二種情況下:

  1. invokevirtual將結果存儲在操作數(shù)棧的頂部

  2. astore_2將結果彈出操作數(shù)棧并將其存儲在局部變量 #2 中

  3. aload_2將局部變量#2 推入操作數(shù)棧的頂部

  4. ifnull檢查操作數(shù)棧的頂部是否為空,如果是,則轉到指令 15,否則繼續(xù)(我們假設它不為空)

  5. aload_2將局部變量#2 推入操作數(shù)棧的頂部

  6. invokevirtual在操作數(shù)棧的頂部調用一個方法,彈出它,然后壓入結果

  7. ireturn從操作數(shù)棧彈出頂部值并返回它

那么有什么區(qū)別呢?第一個調用aload_2一次又一次dup,第二個只調用aload兩次。這里的區(qū)別幾乎沒有。如果查看整個操作過程中堆棧的大小,您會發(fā)現(xiàn)第一個實現(xiàn)將操作數(shù)堆棧增加了一個額外的值(少于 10 個字節(jié),通常為 8 或 4 個字節(jié),具體取決于 64 位或 32 位 JVM ), 但從堆棧內存中加載的局部變量少了一個。第二個使操作數(shù)堆棧稍微小一些,但有一個額外的局部變量加載(讀取:從內存中獲?。?。

歸根結底,這些優(yōu)化的影響非常小,除非是在內存極低的應用程序中,例如嵌入式系統(tǒng)。那么對你來說?做可讀的事情。

如有疑問:“過早優(yōu)化(可能)是萬惡之源?!?除非您知道您的代碼很慢或者可以在運行之前證明它很慢,否則最好編寫可讀的代碼。這幾乎不屬于您應該提前優(yōu)化的關鍵 3%。


查看完整回答
反對 回復 2023-06-08
  • 1 回答
  • 0 關注
  • 138 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號