2013-02-15 11 views
8

Questa è una domanda in due parti, ma non avrebbe senso per i singoli pezzi. Un gran numero di istruzioni dup all'interno del bytecode emette un indicatore di codice scritto male? Dove grande è definito da una percentuale di tutte le istruzioni bytecode. Inoltre, come si fa a riscrivere il codice che genera un'istruzione dup?Bytecode Java "eccessivo" numero di codice "povero" dup considerato?

+0

Per curiosità, cosa provocherebbe una simile domanda? – delnan

+0

Suppongo che tu abbia controllato i collegamenti a destra: http://stackoverflow.com/questions/8594657/why-does-the-following-code-translate-to-a-newew-dup-op-instructions-in- java-byt e http://stackoverflow.com/questions/12438567/java-bytecode-dup – assylias

+0

@assylias sì, certo. Tuttavia, non rispondono alle mie domande specifiche. – Woot4Moo

risposta

7

stiamo parlando javac uscita si sta analizzando o il proprio compilatore/generatore? Se sei preoccupato della qualità del tuo codice Java dal punto di vista di ciò che produce javac, dimenticalo. Prima di tutto javac produce un bytecode subottimale e fa affidamento su JVM/JIT per fare tutte le ottimizzazioni (scelta molto buona). Ma ancora il bytecode è probabilmente molto meglio di qualsiasi cosa si possa inventare rapidamente. È simile alla domanda sulla qualità del codice assembly generato dal compilatore C.

Se si sta generando bytecode te stesso, il numero eccessivo di dup può sembrare cattivo, ma così non potrebbe avere alcun impatto sulle prestazioni. Ricorda che il bytecode viene tradotto all'assemblaggio sul computer di destinazione. JVM è una macchina stack, ma la maggior parte delle architetture in questi giorni sono basate su registri. Il fatto che si usi dup è solo perché alcune istruzioni bytecode sono distruttive (valore pop dallo stack degli operandi durante la lettura). Questo non succede con i registri: puoi leggerli tutte le volte che vuoi. Prendere il seguente codice come un esempio:

new java/lang/Object 
dup 
invokespecial java/lang/Object <init>()V 

dup deve essere utilizzato qui perché invokespecial pops cima alla pila operando. Creare un oggetto solo per perdere un riferimento ad esso dopo aver chiamato il costruttore suona come una cattiva idea. Ma nell'assemblaggio non c'è il dup, nessuna copia e duplicazione dei dati. Avrai solo un registro CPU singolo che punta a java/lang/Object.

In altre parole, il bytecode subottimale è tradotto in assemblaggio "più ottimale" al volo. Solo ... non preoccuparti.

+0

Hmm, hai alcune risorse che indicano perché? Ho fatto la mia giusta parte di ricerche e sembra che la comprensione del set di istruzioni bytecode sia fondamentale per capire cosa fa il programma in fase di runtime. Se riesco a trovare la tesi che lo chiama, lo posterò come link. – Woot4Moo

+2

@ Woot4Moo: che tipo di risorse stai chiedendo? Sono d'accordo che la comprensione del bytecode è molto importante. Sto solo dicendo che 'dup' potrebbe non attivare realmente l'istruzione della singola CPU.È solo un'astrazione che andrà via durante la compilazione JIT. –

+0

Questo è il tipo di risorsa che sto cercando. Dove prova o almeno allude in alcuni casi che il JIT lo butta via. E accetterò una risposta della grande specifica bytecode se è effettivamente dove risiede. – Woot4Moo

2

L'istruzione dup duplica semplicemente l'elemento in cima alla pila operando. Se il compilatore sa che sta per usare un valore più volte in un intervallo relativamente breve, può scegliere di duplicare il valore e tenerlo sulla pila degli operandi fino a quando non è necessario.

Uno dei casi più comuni in cui si vede dup è quando si crea un oggetto e conservarla in una variabile:

Foo foo = new Foo(); 

esecuzione javap -c, si ottiene la seguente bytecode:

0: new #1; //class Foo 
3: dup 
4: invokespecial #23; //Method "<init>":()V 
7: astore_1 

In inglese: l'operazione new crea una nuova istanza dell'oggetto e il invokespecial esegue il costruttore . Dal momento che è necessario il riferimento sullo stack per richiamare il costruttore e anche per memorizzare nella variabile, ha molto senso utilizzare dup (soprattutto perché l'alternativa, l'archiviazione nella variabile e quindi il recupero per eseguire il ctor, potrebbe violare il Modello di memoria Java).

Ecco un caso in cui dove Oracle Java Compiler (1.6) no uso dup quando mi aspetterei a:

int x = 12; 

public int bar(int z) 
{ 
    int y = x + x * 3; 
    return y + z; 
} 

mi aspetto al compilatore di dup il valore di x, dal momento che appare più volte nell'espressione. Invece, itemitted codice che più volte caricato il valore dall'oggetto:

0: aload_0 
1: getfield #12; //Field x:I 
4: aload_0 
5: getfield #12; //Field x:I 
8: iconst_3 
9: imul 
10: iadd 

mi sarei aspettato il dup perché è relativamente costoso per recuperare un valore da un oggetto (anche dopo Hotspot fa la sua magia), mentre le due cellule pila è probabile che si trovino sulla stessa riga della cache.

+0

e il motivo per cui è più economico? – Woot4Moo

+0

"mentre due pile di stack sono probabilmente sulla stessa linea della cache" – parsifal

+0

Anche se, per quel che ne so, Hotspot riconosce le chiamate duplicate 'getfield', riconosce che l'oggetto non è" volatile "e memorizza il valore del campo in una Registrare. – parsifal

1

Se sei preoccupato per l'impatto di dup e le sue relazioni sulle prestazioni, non preoccuparti. La JVM esegue la compilazione just in time, quindi non dovrebbe fare alcuna differenza nelle prestazioni.

Per quanto riguarda la qualità del codice, vi sono due fattori principali che causeranno la generazione di istruzioni dup da parte di Javac. Il primo è l'istanziazione di oggetti, dove è inevitabile. Il secondo è determinati usi dei valori immediati nelle espressioni. Se ne vedi molti più tardi, potrebbe essere un codice di scarsa qualità, dal momento che di solito non desideri espressioni complicate come quelle del tuo codice sorgente (è meno leggibile).

Le altre versioni di dup (dup_x1, dup_x2, dup2, dup2_x1, e dup2_x2) sono particolarmente problematico in quanto istanze di oggetti non usa quelle, quindi significa quasi certamente il più tardi. Ovviamente anche allora non è un grosso problema. Tutto ciò significa che il codice sorgente non è leggibile come potrebbe essere.

Se il codice non è compilato da Java, tutte le scommesse sono disattivate. La presenza o l'assenza di istruzioni non ti dice molto, specialmente nelle lingue i cui compilatori eseguono l'ottimizzazione del tempo di compilazione.

+0

è tutto java fwiw. – Woot4Moo

+0

Il codice legacy è di natura molto procedurale e non utilizzabile (> 500 funzioni di linea e simili) – Woot4Moo

Problemi correlati