javac
presenterà bytecode che è una rappresentazione fedele del programma originale Java che ha generato il bytecode (tranne in alcune situazioni in cui può ottimizzare: costante piegatura e dead-code eliminazione). Tuttavia, l'ottimizzazione può essere eseguita da JVM quando utilizza il compilatore JIT.
Per il primo scenario sembra che la JVM supporta inline (vedi sotto Metodihere e vedere here per un esempio inlining sulla JVM).
Non sono riuscito a trovare esempi di inlining del metodo eseguiti dallo stesso javac
. Ho provato a compilare alcuni programmi di esempio (simile a quello che hai descritto nella tua domanda) e nessuno di loro sembrava allineare direttamente il metodo anche quando era final
. Sembrerebbe che questo tipo di ottimizzazioni sia fatto dal compilatore JIT della JVM e non da javac
.Il "compilatore" menzionato sotto Metodihere sembra essere il compilatore JIT di JSM di HotSpot e non javac
.
Da quello che posso vedere, javac
supporta eliminazione dead-code (vedi esempio per il secondo caso) e costante piegatura. Nel piegamento costante, il compilatore calcolerà in anticipo le espressioni costanti e utilizzerà il valore calcolato anziché eseguire il calcolo durante il runtime. Ad esempio:
public class ConstantFolding {
private static final int a = 100;
private static final int b = 200;
public final void baz() {
int c = a + b;
}
}
compila il seguente bytecode:
Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private static final int a;
private static final int b;
public ConstantFolding();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public final void baz();
Code:
0: sipush 300
3: istore_1
4: return
}
noti che il bytecode ha un sipush 300
anziché s' aload
getfield
s ed un iadd
. 300
è il valore calcolato. Questo vale anche per le variabili private final
. Se a
e b
non erano statiche, il bytecode risultante sarà:
Compiled from "ConstantFolding.java"
public class ConstantFolding extends java.lang.Object{
private final int a;
private final int b;
public ConstantFolding();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 100
7: putfield #2; //Field a:I
10: aload_0
11: sipush 200
14: putfield #3; //Field b:I
17: return
public final void baz();
Code:
0: sipush 300
3: istore_1
4: return
}
Anche qui, un sipush 300
viene utilizzato.
Per il secondo caso (eliminazione dead-code), ho usato il seguente programma di test:
public class InlineTest {
private static final boolean debug = false;
private void baz() {
if(debug) {
String a = foo();
}
}
private String foo() {
return bar();
}
private String bar() {
return "abc";
}
}
che ha pronunciato la seguente bytecode:
Compiled from "InlineTest.java"
public class InlineTest extends java.lang.Object{
private static final boolean debug;
public InlineTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
private void baz();
Code:
0: return
private java.lang.String foo();
Code:
0: aload_0
1: invokespecial #2; //Method bar:()Ljava/lang/String;
4: areturn
private java.lang.String bar();
Code:
0: ldC#3; //String abc
2: areturn
}
Come si può vedere, la foo
è non chiamato affatto in baz
perché il codice all'interno del blocco if
è effettivamente "morto".
HotSpot Sun di Sun's (ora Oracle) combina l'interpretazione del bytecode e della compilazione JIT. Quando il codice byte viene presentato alla JVM, il codice viene inizialmente interpretato, ma la JVM controllerà il bytecode e individuerà le parti che vengono eseguite frequentemente. Copre queste parti in codice nativo in modo che funzionino più velocemente. Per una parte di bytecode che non viene utilizzata così frequentemente, questa compilazione non viene eseguita. Questo è altrettanto valido perché la compilazione ha un sovraccarico. Quindi è davvero una questione di compromesso. Se decidi di compilare tutti i bytecode in nativecode, il codice può avere un ritardo di avvio molto lungo.
Oltre a monitorare il bytecode, la JVM può anche eseguire l'analisi statica del bytecode mentre viene interpretata e caricata per eseguire ulteriori ottimizzazioni.
Se si desidera conoscere i tipi specifici di ottimizzazioni eseguite dalla JVM, this page su Oracle è piuttosto utile. Descrive le tecniche di performance utilizzate in HotSpot JVM.
Risposta breve: Sì, la JVM eseguirà questo tipo di ottimizzazioni. (A condizione che le chiamate di funzione non siano polimorfiche e possano essere determinate staticamente.) – Mysticial
@Mysticial: cosa ti fa pensare così? :) Ho letto questo http://www.ibm.com/developerworks/java/library/j-benchmark1/index.html ma non sono positivo, ho delle risposte. – Schultz9999
Non ho mai detto che * farà * sempre le ottimizzazioni. Ma quel link che hai dato è una buona lettura. – Mysticial