国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

為什么要指令重排序?

Eastboat / 3470人閱讀

摘要:那么我們就應(yīng)該問(wèn)問(wèn)為啥要用指令重排序呢生活類比我們從生活中舉個(gè)例子,假設(shè)你有一箱紅紙,現(xiàn)在要你剪成小紅花貼在窗上。

我們知道java在運(yùn)行的時(shí)候有兩個(gè)地方可能用到重排序,一個(gè)是編譯器編譯的的時(shí)候,一個(gè)是處理器運(yùn)行的時(shí)候。
那么我們就應(yīng)該問(wèn)問(wèn)為啥要用指令重排序呢?

生活類比

我們從生活中舉個(gè)例子,假設(shè)你有一箱紅紙,現(xiàn)在要你剪成小紅花貼在窗上。你有兩種極端的選擇:拿出來(lái)一個(gè),把這個(gè)剪好,再貼上去......一個(gè)一個(gè)依次進(jìn)行;另一種方式是先全部拿出來(lái),然后全部剪好,最后全部貼上去。

那種效率更高?很明顯是后者,因?yàn)榍罢吣憔托枰煌5卦谙渥樱舻逗湍z水之間切換,這個(gè)切換過(guò)程不僅浪費(fèi)時(shí)間,還耗費(fèi)精力。但是后者一直做一個(gè)工作也很無(wú)聊,還會(huì)導(dǎo)致半天了窗上一朵花都沒有,會(huì)給你帶來(lái)失落感,所以比較合適的做法就是拿出來(lái)一疊,把這一疊剪好,貼上去。這樣既不無(wú)聊,也減少了切換次數(shù),提高了工作效率。

再想想,如果有三個(gè)人,一個(gè)負(fù)責(zé)拿,一個(gè)負(fù)責(zé)剪,一個(gè)負(fù)責(zé)貼,就更快了。

分析

編譯期重排序有啥好處?CPU計(jì)算的時(shí)候要訪問(wèn)值,如果常常利用到寄存器中已有的值就不用去內(nèi)存讀取了,比如說(shuō)

int a = 1;
int b = 1;
a = a + 1;
b = b +1 ;

就可能沒有

int a = 1;
a = a + 1;
int b = 1;
b = b +1 ;

性能好,因?yàn)楹笳呖梢?a或b可能在寄存器中了。

處理器為啥要重排序?因?yàn)橐粋€(gè)匯編指令也會(huì)涉及到很多步驟,每個(gè)步驟可能會(huì)用到不同的寄存器,CPU使用了流水線技術(shù),也就是說(shuō),CPU有多個(gè)功能單元(如獲取、解碼、運(yùn)算和結(jié)果),一條指令也分為多個(gè)單元,那么第一條指令執(zhí)行還沒完畢,就可以執(zhí)行第二條指令,前提是這兩條指令功能單元相同或類似,所以一般可以通過(guò)指令重排使得具有相似功能單元的指令接連執(zhí)行來(lái)減少流水線中斷的情況。

我們寫一段代碼來(lái)試試:

package *****;

/**
 * reorder
 * @author Mageek Chiu
 * @date 2018/5/25 0025:12:49
 */
public class ReOrder {

    public int value ;

    private ReOrder(int value) {
        this.value = value;
    }

    public static void main(String... args){
        ReOrder reOrder = new ReOrder(111);
        ReOrder reOrder1 = new ReOrder(222);
        ReOrder reOrder2 = new ReOrder(333);
        System.out.println(add1(reOrder,reOrder1,reOrder2));
    }

    static int add1(ReOrder reOrder,ReOrder reOrder1,ReOrder reOrder2){
        int result = 0;

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;//***

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;

        return result;

    }

}

運(yùn)行結(jié)果中:

 # {method} {0x000000001c402c80} "add1" "(*****/ReOrder;*****/ReOrder;*****/ReOrder;)I" in "*****/ReOrder"
  # parm0:    rdx:rdx   = "*****/ReOrder"
  # parm1:    r8:r8     = "*****/ReOrder"
  # parm2:    r9:r9     = "*****/ReOrder"
  #           [sp+0x20]  (sp of caller)
  0x00000000032a86c0: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x00000000032a86c7: push    rbp
  0x00000000032a86c8: sub     rsp,10h           ;*synchronization entry
                                                ; - *****.ReOrder::add1@-1 (line 24)

  0x00000000032a86cc: mov     r11d,dword ptr [rdx+0ch]
                                                ;*getfield value
                                                ; - *****.ReOrder::add1@4 (line 26)
                                                ; implicit exception: dispatches to 0x00000000032a86ff
  0x00000000032a86d0: mov     r10d,dword ptr [r8+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@11 (line 27)
                                                ; implicit exception: dispatches to 0x00000000032a870d
  0x00000000032a86d4: mov     r9d,dword ptr [r9+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@18 (line 28)
                                                ; implicit exception: dispatches to 0x00000000032a8719
  0x00000000032a86d8: mov     eax,r11d
  0x00000000032a86db: add     eax,r10d
  0x00000000032a86de: add     eax,r9d
  0x00000000032a86e1: add     eax,r11d
  0x00000000032a86e4: add     eax,r10d
  0x00000000032a86e7: add     eax,r9d
  0x00000000032a86ea: add     eax,r11d
  0x00000000032a86ed: add     eax,r10d
  0x00000000032a86f0: add     eax,r9d           ;*iadd

也就是先用mov把方法里面所需要的三個(gè)value加載了,再統(tǒng)一用add進(jìn)行加法運(yùn)算。

現(xiàn)在我們把//***哪一行注釋掉,運(yùn)行結(jié)果如下:

[Constants]
  # {method} {0x000000001c052c78} "add1" "(*****/ReOrder;*****/ReOrder;*****/ReOrder;)I" in "*****/ReOrder"
  # parm0:    rdx:rdx   = "*****/ReOrder"
  # parm1:    r8:r8     = "*****/ReOrder"
  # parm2:    r9:r9     = "*****/ReOrder"
  #           [sp+0x20]  (sp of caller)
  0x0000000002f47d40: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x0000000002f47d47: push    rbp
  0x0000000002f47d48: sub     rsp,10h           ;*synchronization entry
                                                ; - *****.ReOrder::add1@-1 (line 24)

  0x0000000002f47d4c: mov     r11d,dword ptr [rdx+0ch]
                                                ;*getfield value
                                                ; - *****r.ReOrder::add1@4 (line 26)
                                                ; implicit exception: dispatches to 0x0000000002f47d7c
  0x0000000002f47d50: mov     r10d,dword ptr [r8+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@11 (line 27)
                                                ; implicit exception: dispatches to 0x0000000002f47d89
  0x0000000002f47d54: mov     r9d,dword ptr [r9+0ch]  ;*getfield value
                                                ; - *****::add1@32 (line 32)
                                                ; implicit exception: dispatches to 0x0000000002f47d95
  0x0000000002f47d58: mov     eax,r11d
  0x0000000002f47d5b: add     eax,r10d
  0x0000000002f47d5e: add     eax,r11d
  0x0000000002f47d61: add     eax,r10d
  0x0000000002f47d64: add     eax,r9d
  0x0000000002f47d67: add     eax,r11d
  0x0000000002f47d6a: add     eax,r10d
  0x0000000002f47d6d: add     eax,r9d           ;*iadd

依然是先把所有value都用mov指令加載后再進(jìn)行加法運(yùn)算。
總結(jié)起來(lái)就是不管代碼里這個(gè)值使用順序多靠后,都先用mov加載后再使用add對(duì)這個(gè)值進(jìn)行運(yùn)算。

注意,上面的運(yùn)行參數(shù)為-Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*ReOrder.add1 -XX:+PrintCompilation
Xcomp 含義是使用編譯模式而不是解釋模式, -XX:CompileCommand=print,*ReOrder.add1表示只打印這個(gè)方法,-XX:+PrintCompilation表示打印方法名稱。
需要插件hsdis,編譯好后放在jdk的jre的bin的server中就好,具體環(huán)境搭建可以參閱這里

分析不對(duì)的地方請(qǐng)輕拍。
訪問(wèn)原文

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69559.html

相關(guān)文章

  • Java并發(fā)編程之指令重排

    摘要:安全性小結(jié)我們上邊介紹了原子性操作內(nèi)存可見性以及指令重排序三個(gè)在多線程執(zhí)行過(guò)程中會(huì)影響到安全性的問(wèn)題。 指令重排序 如果說(shuō)內(nèi)存可見性問(wèn)題已經(jīng)讓你抓狂了,那么下邊的這個(gè)指令重排序的事兒估計(jì)就要罵娘了~這事兒還得從一段代碼說(shuō)起: public class Reordering { private static boolean flag; private static in...

    microcosm1994 評(píng)論0 收藏0
  • 從JVM并發(fā)看CPU內(nèi)存指令重排

    摘要:處理器通過(guò)緩存能夠從數(shù)量級(jí)上降低內(nèi)存延遲的成本這些緩存為了性能重新排列待定內(nèi)存操作的順序。從上述觸發(fā)步驟中,可以看到第步發(fā)生了指令重排序,并導(dǎo)致第步讀到錯(cuò)誤的數(shù)據(jù)。內(nèi)存屏障是用來(lái)防止出現(xiàn)指令重排序的利器之一。 這兩天,我拜讀了 Dennis Byrne 寫的一片博文Memory Barriers and JVM Concurrency (中譯文內(nèi)存屏障與JVM并發(fā))。 文中提到: ...

    vboy1010 評(píng)論0 收藏0
  • 《深入理解 Java 內(nèi)存模型》讀書筆記

    摘要:前提深入理解內(nèi)存模型程曉明著,該書在以前看過(guò)一遍,現(xiàn)在學(xué)的東西越多,感覺那塊越重要,于是又再細(xì)看一遍,于是便有了下面的讀書筆記總結(jié)。同步同步是指程序用于控制不同線程之間操作發(fā)生相對(duì)順序的機(jī)制。線程之間的通信由內(nèi)存模型控制。 showImg(https://segmentfault.com/img/remote/1460000013474312?w=1920&h=1271); 前提 《深...

    xuexiangjys 評(píng)論0 收藏0
  • 深入理解Java內(nèi)存模型(一)——基礎(chǔ)

    摘要:線程之間的通信由內(nèi)存模型本文簡(jiǎn)稱為控制,決定一個(gè)線程對(duì)共享變量的寫入何時(shí)對(duì)另一個(gè)線程可見。為了保證內(nèi)存可見性,編譯器在生成指令序列的適當(dāng)位置會(huì)插入內(nèi)存屏障指令來(lái)禁止特定類型的處理器重排序。 并發(fā)編程模型的分類 在并發(fā)編程中,我們需要處理兩個(gè)關(guān)鍵問(wèn)題:線程之間如何通信及線程之間如何同步(這里的線程是指并發(fā)執(zhí)行的活動(dòng)實(shí)體)。通信是指線程之間以何種機(jī)制來(lái)交換信息。在命令式編程中,線程之間的...

    jsdt 評(píng)論0 收藏0
  • 《深入理解 Java 內(nèi)存模型》讀書筆記

    摘要:前提深入理解內(nèi)存模型程曉明著,該書在以前看過(guò)一遍,現(xiàn)在學(xué)的東西越多,感覺那塊越重要,于是又再細(xì)看一遍,于是便有了下面的讀書筆記總結(jié)。同步同步是指程序用于控制不同線程之間操作發(fā)生相對(duì)順序的機(jī)制。線程之間的通信由內(nèi)存模型控制。 showImg(https://mmbiz.qpic.cn/mmbiz_jpg/1flHOHZw6RtPu3BNx3zps1JhSmPICRw7QgeOmxOfTb...

    姘存按 評(píng)論0 收藏0
  • 什么雙重檢查鎖模式需 volatile ?

    摘要:注意,禁止指令重排序在之后才被修復(fù)使用局部變量?jī)?yōu)化性能重新查看中雙重檢查鎖定代碼。幫助文檔雙重檢查鎖定與延遲初始化有關(guān)雙重檢查鎖定失效的說(shuō)明 雙重檢查鎖定(Double check locked)模式經(jīng)常會(huì)出現(xiàn)在一些框架源碼中,目的是為了延遲初始化變量。這個(gè)模式還可以用來(lái)創(chuàng)建單例。下面來(lái)看一個(gè) Spring 中雙重檢查鎖定的例子。 showImg(https://segmentfaul...

    geekzhou 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<