In Java esiste una differenza di prestazioni tra il riferimento a un campo tramite getter rispetto a una variabile?

StackOverflow https://stackoverflow.com/questions/1195849

Domanda

Ci sono differenze tra il fare

Field field = something.getSomethingElse().getField();
if (field == 0) {
//do something    
}
somelist.add(field);

contro

if (something.getSomethingElse().getField() == 0) {
//do something    
}
somelist.add(something.getSomethingElse().getField());

I riferimenti al campo tramite getter comportano una penalità in termini di prestazioni o equivale a fare riferimento a una variabile assegnata? Capisco che la variabile è solo un riferimento allo spazio di memoria, quindi il getter dovrebbe essere solo un altro modo per raggiungere quello spazio di memoria.

Tieni presente che questa è una questione accademica (scuola di semplici curiosi) piuttosto che pratica.

È stato utile?

Soluzione

Supponendo che getSomethingElse() è definito come

public SomethingElse getSomethingElse() {
    return this.somethingElse;
}

differenza di prestazioni sarà minimo (o zero se si otterrà inline). Tuttavia, nella vita reale non si può essere sempre sicuri che sia il caso - ci può essere qualche trasformazione accade dietro le quinte (non necessariamente nell'oggetto stesso, ma, per esempio, mediante delega AOP). Quindi salvare il risultato nella variabile per l'accesso di ripetizione può essere una buona idea.

Altri suggerimenti

E 'un danno trascurabile. Non preoccuparti di troppo o cadrete preda di ottimizzazione prematura. Se l'applicazione è lenta, non è questo il motivo per cui.

C'è una differenza in quanto le variabili di accesso attraverso Getters risultati in una chiamata di metodo. La JVM potrebbe in teoria essere in grado di ottimizzare la chiamata al metodo via in alcune circostanze, ma è una chiamata di metodo.

Detto questo, se il problema più grande collo di bottiglia o le prestazioni nel codice è in testa da metodi di accesso, direi che non si dispone di molto da preoccuparsi.

C'è una penalizzazione delle prestazioni (che può essere così piccolo che è trascurabile) Eppure, la JVM può inline questa e tutte le chiamate per migliorare le prestazioni.

Sarebbe meglio se si lascia il secondo modo.

No, se si dispone di una buona JVM, come HotSpot di Sun. Sarà in-line e compilare (in codice nativo) i getter.

Utilizzando getter è generalmente una buona pratica, come una misura difensiva, e informazioni generali nascondere.

Un punto da notare se si utilizza Java per la scrittura di applicazioni Android è qui: http://developer.android.com/training/articles/perf-tips .html # GettersSetters

  

Nel lingue native come il C ++ è pratica comune l'uso di getter (i =   getCount ()) invece di accedere direttamente al campo (i = mCount). Questo   è un'ottima abitudine per C ++ ed è spesso praticata in un altro oggetto   linguaggi orientati come C # e Java, perché il compilatore di solito può   inline l'accesso, e se avete bisogno di limitare o l'accesso campo di debug   è possibile aggiungere il codice in qualsiasi momento.

     

Tuttavia, questa è una cattiva idea su Android. sono chiamate a metodi virtuali   costoso, molto più di quanto le ricerche sul campo istanza. E 'ragionevole   a seguire le pratiche comuni di programmazione object-oriented e hanno   getter e setter nell'interfaccia pubblica, ma all'interno di una classe che si   dovrebbe sempre accedere direttamente ai campi.

     

Senza un JIT, accesso campo diretto è circa 3 volte più veloce di invocare una   getter banale. Con il JIT (dove è a buon mercato come l'accesso campo diretto   l'accesso a un locale), accesso diretto campo è di circa 7 volte più veloce di   invocando un getter banale.

     

Si noti che se si sta utilizzando ProGuard, si può avere il meglio di entrambi   mondi perché ProGuard possono inline di accesso per voi.

Se il metodo è un semplice getter senza elaborazione coinvolti, non è un problema. Se si tratta di vasta calcolo, una proprietà non avrebbe fatto quello che si vuole in ogni caso.

L'unica volta che avevo preoccuparvi di qualsiasi differenza è in un loop stretto con un enorme numero di iterazioni (molte migliaia). Anche allora questo è probabilmente solo un problema se si sta utilizzando gli aspetti di tessere elaborazione aggiuntiva (ad esempio la registrazione), ciò può comportare la creazione di migliaia di oggetti extra (ad esempio joinpoint e parametro autoboxing) e problemi di GC derivano.

Non mi preoccuperei per la differenza di prestazioni. Faresti meglio a non pensarci e invece trascorrere del tempo sul profiling il codice in uno scenario realistico. È molto probabile trovare che le parti lente del vostro programma non sono dove si pensa che sono.

Questo post parla della VM CLI anziché della JVM, ma ognuna è in grado di fare cose simili, quindi credo che sia rilevante.

Sto gestendo questo particolare problema in modo speciale per il mio JIT.Tieni presente che la descrizione qui è concettuale e il codice la implementa in modo leggermente diverso per motivi di prestazioni.Quando carico un assembly, prendo nota nel descrittore del metodo se restituisce semplicemente un campo membro.Quando eseguo JIT con altri metodi in seguito, sostituisco all call istruzioni a questi metodi nel codice byte con a ldfld istruzione prima di passarla al generatore di codice nativo.In questo modo posso:

  1. Risparmia tempo nel JIT (ldfld richiede meno tempo del processore per JIT rispetto a call).
  2. Proprietà in linea anche nel file compilatore di base.
  3. In generale garantisce che l'utilizzo del modello proprietà pubbliche/campi privati ​​non comporterà una riduzione delle prestazioni di alcun tipo quando il debugger è scollegato.(Quando è collegato un debugger non posso incorporare le funzioni di accesso.)

Non ho dubbi che i grandi nomi delle tecnologie VM stiano già implementando qualcosa di simile (e probabilmente migliore) nei loro prodotti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top