2012-01-05 12 views
7

È noto che il linguaggio Java consente ai compilatori di riorganizzare le righe del codice compilato purché il riordino non faccia alcuna differenza per la semantica del codice. Tuttavia, è richiesto al compilatore solo di preoccuparsi della semantica vista dal thread corrente . Se questa ri-ordine colpisce la semantica in una situazione multithread, di solito provoca problemi di concorrenza (visibilità memoria)Modello di memoria Java: compilatore che riordina le righe di codice

La mia domanda (s):

  1. ciò che si ottiene, consentendo questo freedm al compilatore? È davvero possibile per il compilatore produrre codice più efficiente riorganizzando il codice? Devo ancora vedere un caso pratico per questo. A volte mi rendo conto che i vantaggi, se presenti, superano di gran lunga i rischi di concorrenza che questo può comportare.

  2. C'è un modo in cui il programmatore può dire al compilatore di non riorganizzare righe come questa? So che usare le primitive di sincronizzazione gestisce in modo efficace gli effetti collaterali del riorganizzare, ma sto chiedendo se c'è un modo diretto (opzione del compilatore) per disattivarlo?

risposta

8

Il javac compilatore ha esegue vicino a nessun ottimizzazioni.

Il compilatore nativo JIT può riordinare le istruzioni in caso di problemi di ordinamento della memoria. Tuttavia, la CPU può anche riordinare le istruzioni e gli aggiornamenti di memoria che hanno lo stesso effetto.

Cosa si ottiene consentendo questo freedm al compilatore?

Il vantaggio principale è la portabilità del codice. Più garanzie fornite, più è difficile garantire che ogni piattaforma lo faccia effettivamente.

C'è anche un significativo miglioramento delle prestazioni permettendo alla CPU di eseguire le istruzioni come e quando può, piuttosto che in un ordine rigoroso.

È davvero possibile che il compilatore produca codice più efficiente riorganizzando il codice?

Sì. ma il riordino fatto dalla CPU è più significativo.

Devo ancora vedere un caso pratico per questo. A volte mi rendo conto che i vantaggi, se presenti, superano di gran lunga i rischi di concorrenza che questo può comportare.

C'è un modo in cui il programmatore può dire al compilatore di non riorganizzare righe come questa?

Questo è il motivo per utilizzare le barriere di memoria come volatile, synchronized blocchi e Lock.Quando li usi, ottieni garanzie sulla sicurezza del filo.

So che l'uso delle primitive di sincronizzazione gestisce in modo efficace gli effetti collaterali del riorganizzazione, ma sto chiedendo se esiste un modo diretto (opzione del compilatore) per disattivarlo?

È possibile disattivare JIT, ma la maggior parte del riordino viene eseguita dalla CPU in modo da non ottenere molto.

Evitare di riordinare gli aggiornamenti è una parte così piccola del problema di sicurezza dei thread (il problema più grande è che è oscuro e si verifica raramente che lo rende difficile) E una volta scritto il codice thread-safe, questo è alleviato.

2

Il processo di riorganizzazione del bytecode è gestito dal compilatore JIT (Just in Time). È possibile impedire che l'esecuzione con la seguente opzione:

-Djava.compiler=NONE 

Vedere più qui: http://www.cs.swarthmore.edu/~newhall/unixhelp/debuggingtips_Java.html

+1

Questo non fermerà le istruzioni di riordino della CPU. ;) –

+0

E rende il tuo programma eseguito molto lento, quindi questa non è un'opzione che è utile per qualsiasi uso di produzione. – Jesper

2

È davvero possibile che il compilatore produca codice più efficiente riorganizzando il codice?

Oh sì, lo è!

Uno dei fatti della vita nell'architettura dei computer moderni è che la memoria è il collo di bottiglia principale delle prestazioni. La CPU può eseguire il registro per registrare le istruzioni molte volte più velocemente di quanto possa leggere e scrivere nella memoria principale. Ecco perché i chip ad alte prestazioni hanno 2 o 3 livelli di memoria cache. Inoltre, le CPU tipiche utilizzano il pipelining per consentire l'esecuzione di più istruzioni nello stesso momento.

Per ottenere il massimo dalle prestazioni con CPU con queste proprietà, il compilatore (e la CPU stessa) devono essere in grado di riordinare le istruzioni per sfruttare al meglio la larghezza di banda della memoria e mantenere la pipeline piena. Il codice nativo deve inoltre essere in grado di utilizzare valori (di variabili) salvati nei registri e ridurre al minimo l'uso di istruzioni di barriera di memoria che attendono che le scritture di memoria si propaghino nella memoria principale. Questi sono consentiti solo (in Java) perché il modello di memoria Java consente il riordino.

Nota: stiamo parlando di una significativa accelerazione qui: forse una velocità da 3 a 5 volte.

Se si desidera avere un'idea di quanto, è necessario utilizzare un'applicazione intensiva a variabile di istanza e riscriverla in modo che tutte le variabili di istanza siano volatile. (Ciò ridurrà l'ambito per il riordino e farà sì che tutte le letture e le scritture vadano in memoria.) Quindi confrontate le prestazioni dell'applicazione originale con la versione modificata.

Problemi correlati