JIT typu Hotspot wprowadza tylko metody, których rozmiar jest mniejszy niż określony (konfigurowalny). Tak więc użycie mniejszych metod pozwala na bardziej inlineing, co jest dobre.
Zobacz różne opcje inline na this page.
EDIT
Aby rozwinąć trochę:
- jeśli metoda jest mały, zostanie on inlined więc jest mała szansa, aby uzyskać ukarany za podzielenie kodu w małych sposobów.
- w niektórych przypadkach metody dzielenia mogą powodować więcej wstawiania.
Przykład (pełny kod mają te same numery linii, jeśli spróbujesz go)
package javaapplication27;
public class TestInline {
private int count = 0;
public static void main(String[] args) throws Exception {
TestInline t = new TestInline();
int sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += t.m();
}
System.out.println(sum);
}
public int m() {
int i = count;
if (i % 10 == 0) {
i += 1;
} else if (i % 10 == 1) {
i += 2;
} else if (i % 10 == 2) {
i += 3;
}
i += count;
i *= count;
i++;
return i;
}
}
Po uruchomieniu tego kodu z następującymi flagami JVM: -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:FreqInlineSize=50 -XX:MaxInlineSize=50 -XX:+PrintInlining
(tak mam używane wartości to udowodnić moją Sprawa: m
jest za duża, ale zarówno refaktoryzowane m
, jak i m2
są poniżej progu - z innymi wartościami możesz otrzymać inne wyniki.
Zobaczysz, że m()
i main()
uzyskać skompilowany, ale m()
nie zostanie inlined:
56 1 javaapplication27.TestInline::m (62 bytes)
57 1 % javaapplication27.TestInline::main @ 12 (53 bytes)
@ 20 javaapplication27.TestInline::m (62 bytes) too big
Można również sprawdzić wygenerowany montaż potwierdzić, że m
nie inlined (użyłem te flagi JVM: -XX:+PrintAssembly -XX:PrintAssemblyOptions=intel
) - będzie to wyglądać tak:
0x0000000002780624: int3 ;*invokevirtual m
; - javaapplication27.TestInline::[email protected] (line 10)
Jeśli byłaby kodu takiego (mam ekstrakcji if/else w osobnej metody):
public int m() {
int i = count;
i = m2(i);
i += count;
i *= count;
i++;
return i;
}
public int m2(int i) {
if (i % 10 == 0) {
i += 1;
} else if (i % 10 == 1) {
i += 2;
} else if (i % 10 == 2) {
i += 3;
}
return i;
}
Zobaczysz następujące czynności kompilacji:
60 1 javaapplication27.TestInline::m (30 bytes)
60 2 javaapplication27.TestInline::m2 (40 bytes)
@ 7 javaapplication27.TestInline::m2 (40 bytes) inline (hot)
63 1 % javaapplication27.TestInline::main @ 12 (53 bytes)
@ 20 javaapplication27.TestInline::m (30 bytes) inline (hot)
@ 7 javaapplication27.TestInline::m2 (40 bytes) inline (hot)
Więc m2
dostaje inlined do m
, których można się spodziewać, więc jesteśmy z powrotem do oryginalnego scenariusza. Ale kiedy kompiluje się main
, to faktycznie dodaje do niej całą treść. Na poziomie zespołu oznacza to, że nie znajdziesz już żadnych instrukcji dotyczących invokevirtual
. Znajdziesz linie takie jak ta:
0x00000000026d0121: add ecx,edi ;*iinc
; - javaapplication27.TestInline::[email protected] (line 33)
; - javaapplication27.TestInline::[email protected] (line 24)
; - javaapplication27.TestInline::[email protected] (line 10)
, gdzie zasadniczo wspólne instrukcje są "wspólne".
Wnioski
Nie jestem mówiąc, że ten przykład jest reprezentatywny, ale wydaje się udowodnić kilka punktów:
- stosując mniejszą sposób poprawia czytelność w kodzie
- mniejsze metody będą ogólnie być zainicjowanym, więc najprawdopodobniej nie zapłacisz kosztu dodatkowej metody wywołania (będzie to neutralne pod względem wydajności).
- przy użyciu mniejszych metod może poprawić inline globalnie w pewnych okolicznościach, jak pokazano na przykładzie powyżej
i wreszcie: jeśli część kodu jest bardzo krytyczny dla wydajności, że te rozważania znaczenia, należy zbadać wyjście JIT do dostrojenia Twój kod i ważny profil przed i po.
Ogólny proces kompilacji JIT składa się z następujących kroków ... http: //publib.boulder.ibm.com/infocenter/java7sdk/v7r0/index.jsp? Topic =% 2Fcom.ibm.java.win.70.doc % 2Fdiag% 2Foundstanding% 2Fjit_overview.html, ale nie mówi o tym, jak jit obsługuje duże lub małe moduły. – AurA