2016-01-15 15 views
14

Ho questo codice (messo da parte la sua adeguatezza per ora):comportamento diverso in esecuzione e il debug del programma Java, Eclipse

Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache"); 
    Field cacheField = cacheClass.getDeclaredField("cache"); 
    cacheField.setAccessible(true); 
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL); 

    Integer betterCache[] = new Integer[255]; 
    for (int i = 0; i < betterCache.length; i++) { 
     betterCache[i] = 20; 
    } 
    cacheField.set(null, betterCache); 
    System.out.println(10); 
    System.out.println((Integer) 10); 

mi aspetto il secondo println per stampare 20, come ho sostituito caching delle Integers con 20. Quando eseguo il debug di un programma in Eclipse, come mi aspetto, ottiene il valore dalla cache e stampa 20, mentre ne stampa 10 in entrambi i casi quando lo eseguo da IDE o invocando java. Come può essere spiegato questo comportamento?

UPD: Funziona in questo modo se compilato con 1.8 javac. Stampa 10 e 20 se compilato con la versione 1.6.

+0

Si sta stampando 10 in entrambi i casi. Allora perché dovrebbe stampare 20? –

+0

Nel secondo caso è un oggetto, quindi chiama il metodo 'Integer.valueOf' per stamparlo, e in quel metodo prende valori dalla cache che ho appena sostituito con un array riempito con 20. – cliffroot

+2

Interessante problema (anche se stai giocando con il fuoco). – mks

risposta

2

EDIT

ero completamente sbagliato

Sicuramente si sta giocando con il fuoco, nel mio punto di vista, questo è per un condizioni di gara (filo pericoloso in Java 8). Se verificate questo:

Class<?> cacheClass = Class.forName("java.lang.Integer$IntegerCache"); 
    Field cacheField = cacheClass.getDeclaredField("cache"); 
    cacheField.setAccessible(true); 
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(cacheField, cacheField.getModifiers() & ~Modifier.FINAL); 
    Integer firstCache[] = (Integer[])cacheField.get(null); 
    Integer betterCache[] = new Integer[255]; 
    for (int i = 0; i < betterCache.length; i++) { 
     betterCache[i] = 20; 
    } 
    System.out.println(firstCache == betterCache); 
    cacheField.set(null, betterCache); 
    System.out.println(10); 
    for (int i = 0; i < 1000000; i++) { 
     System.out.println((Integer) 10);  
    } 

Vedrete la masterizzazione Java.

+0

Grazie per la risposta. Ancora non capisco perché cambiare '20' (in pratica chiama a' valueOf') per creare un nuovo valore cambia questo comportamento. Non sembra che sia valutato in fase di compilazione (sebbene la roba del bytecode sia molto poco chiara per me), poiché nel bytecode per entrambe le versioni c'è la stessa istruzione 'bipush 10' per il secondo' println'. Si prega di vedere anche l'aggiornamento alla mia domanda – cliffroot

+1

@cliffroot Non lo so, ma posso vedere le differenze con/senza punti di interruzione In modalità di debug. Sto cominciando a pensare in condizioni di gara. –

+1

@cliffroot Ho modificato! –

4

Questo è sicuramente causato da Just in Time Compiler. Si dovrebbe aggiungere -XX: + PrintCompilation alle opzioni JVM, è anche più visibile se eseguire iterazioni

System.out.println((Integer) 10); 

un sacco di volte. Si noterà che la compilazione

java.lang.Integer::valueOf (32 bytes) 

e

java.nio.ByteBuffer::arrayOffset (35 bytes) 

influenza il risultato.

+0

Ti spiace spiegare l'output di '-xx: + PrintCompilation' ... L'ho passato ma non riuscivo davvero a capire molto ... – Codebender