Мы знаем, что переупорядочивание может использоваться в двух местах во время работы Java: одно — при компиляции компилятора, а другое — во время работы процессора. Тогда мы должны спросить, зачем использовать переупорядочение инструкций?
аналогия с жизнью
Возьмем пример из жизни Допустим, у вас есть коробка из красной бумаги, и теперь вы хотите вырезать маленькие красные цветочки и приклеить их на окно. У вас есть два крайних варианта: взять один, вырезать это и вставить... один за другим; другой способ - сначала взять все, затем вырезать все и вставить все в конце.
Что эффективнее? Очевидно последнее, потому что с первым вам нужно постоянно переключаться между коробками, ножницами и клеем, что является пустой тратой времени и энергии. Но последнее тоже очень скучно постоянно заниматься делом, а также приведет к длительному времени без цветка на окне, что принесет вам чувство утраты, поэтому целесообразнее вынести стопку , вырежьте этот стек и вставьте его. Это не скучно, но также снижает количество переключений и повышает эффективность работы.
Подумайте еще раз, если есть три человека, один отвечает за взятие, один отвечает за резку, а другой отвечает за приклеивание, то это будет быстрее.
анализировать
Каковы преимущества переупорядочения во время компиляции? Когда ЦП вычисляет, ему необходимо получить доступ к значению.Если часто используется существующее значение в регистре, нет необходимости читать его из памяти.Например,
int a = 1;
int b = 1;
a = a + 1;
b = b +1 ;
А может и не быть
int a = 1;
a = a + 1;
int b = 1;
b = b +1 ;
Хорошая производительность, так как последний может либо a, либо b уже быть в регистре.
Почему процессоры должны быть переупорядочены? Поскольку инструкция сборки также включает много шагов, каждый шаг может использовать разные регистры, ЦП использует конвейерную технологию, то есть ЦП имеет несколько функциональных блоков (таких как выборка, декодирование, операция и результат), Инструкции также делятся на несколько единицы, поэтому вторая инструкция может быть выполнена до завершения выполнения первой инструкции.Предпосылка состоит в том, что функциональные единицы двух инструкций одинаковы или похожи.Поэтому, как правило, можно изменить порядок инструкций, чтобы они имели схожие Инструкции выполняются одна за другой, чтобы уменьшить количество прерываний конвейера.
Давайте напишем кусок кода, чтобы попробовать:
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;
}
}
В рабочем результате:
# {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
Поместите три требуемых в методvalue
загружен, а затем использовать его равномерноaddВыполните операцию сложения.
Теперь мы ставим//***
Какая строка закомментирована, текущий результат выглядит следующим образом:
[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Операция сложения выполняется после загрузки инструкции. Подводя итог, неважно, как позже значение будет использовано в коде, используйте его первым.movиспользовать после загрузкиaddРаботайте с этим значением.
Обратите внимание, что приведенные выше параметры запуска-Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*ReOrder.add1 -XX:+PrintCompilation
.Xcomp
Смысл в том, чтобы использовать скомпилированный режим вместо интерпретируемого,-XX:CompileCommand=print,*ReOrder.add1
Указывает, что печатается только этот метод,-XX:+PrintCompilation
Указывает имя метода печати.
требуется плагинhsdis, поставить после компиляцииjdk的jre的bin的server
Хорошо быть посередине.здесь
Пожалуйста, нажмите, если анализ неверен. доступоригинальный