2015-10-05 12 views
5

Attualmente sto rivedendo un PullRequest che contiene questo:Evitare indirezione e metodo ridondante chiamate

-  for (int i = 0; i < outgoingMassages.size(); i++) { 
+  for (int i = 0, size = outgoingMassages.size(); i < size; i++) 

https://github.com/criticalmaps/criticalmaps-android/pull/52

in qualche modo ci si sente male a me - potrebbe pensare che la VM sta facendo queste ottimizzazioni - ma non posso Dillo davvero. Mi piacerebbe avere qualche input se questo cambiamento può avere senso - o una conferma che ciò avvenga sul lato VM.

risposta

5

No, non è sicuro che la macchina virtuale cambierà il codice da

-  for (int i = 0; i < outgoingMassages.size(); i++) { 

a

+  for (int i = 0, size = outgoingMassages.size(); i < size; i++) 

Nel suo ciclo for, è possibile che il outgoingMassages cambierà la sua dimensione. Quindi questa ottimizzazione non può essere applicata dalla JVM. Anche un'altra discussione può modificare la dimensione outgoingMassages se si tratta di una risorsa condivisa.

La JVM può modificare il codice solo se il comportamento non cambia. Ad esempio, può sostituire un elenco di concatenazioni di stringhe con una sequenza di append a StringBuilder oppure può incorporare una semplice chiamata di metodo oppure può calcolare un valore fuori dal ciclo se è un valore costante.

+0

E se sappiamo che 'outgoingMassages.size()' non verrà modificato? Non sarà ottimizzato, perché non abbiamo bisogno di chiamare l'oggetto 'outgoingMassages' e il metodo' size() 'ogni volta? – HendraWD

+0

@HendraWD se si sa che la dimensione di outgoingMessages non viene modificata durante il ciclo che assegna la dimensione a una variabile è un'ottimizzazione che può essere eseguita. Tuttavia, in generale, è meglio concentrarsi su come ridurre il tempo nel codice all'interno del ciclo. –

+0

ok, grazie per la conferma :) – HendraWD

1

La VM non eseguirà queste ottimizzazioni. Poiché è possibile che la dimensione() - Metodo non restituisca lo stesso risultato ogni chiamata. Quindi il metodo deve essere chiamato ogni iterazione.

Tuttavia, se la dimensione è un metodo getter semplice, l'impatto sulle prestazioni è molto ridotto. Probabilmente non misurabile. (In alcuni casi può consentire a Java di utilizzare la parallelizzazione che potrebbe fare la differenza, ma ciò dipende dal contenuto del loop).

La differenza maggiore può essere quella di garantire che il ciclo for abbia una quantità di iterazioni note in anticipo. Non mi sembra sensato in questo esempio. Ma forse il metodo chiamato potrebbe restituire risultati mutevoli indesiderati?

0

Se il metodo size() nella raccolta assegna semplicemente il valore di un campo privato, la VM ottimizzerà la maggior parte di ciò (ma non del tutto). Lo farà inserendo il metodo size(), in modo che diventi solo l'accesso a quel campo.

Il bit rimanenti che non andranno ottimizzato è che size nel nuovo codice I viene trattato come final, e quindi costante, mentre il campo prelevato dalla raccolta non saranno trattati come final (forse è modificato da un altro thread). Quindi nel caso originale il campo verrà letto in ogni iterazione, ma nel nuovo caso non lo farà.

0

E 'probabile che qualsiasi ottimizzatore decente - sia al VM o nel compilatore - riconosceranno:

class Messages { 

    int size; 

    public int size() { 
     return size; 
    } 
} 

public void test() { 
    Messages outgoingMassages = new Messages(); 
    for (int i = 0; i < outgoingMassages.size(); i++) { 

    } 
} 

e ottimizzare al

for (int i = 0; i < outgoingMassages.size; i++) { 

fare l'extra - non testato - ottimizzazione dovrebbe pertanto essere considerato evil.

0

Procedimento invocazione accaderà ciascuna iterazione del ciclo e non è libera dei costi. Dal momento che non è possibile prevedere quanto spesso ciò accade chiamandolo una volta sarà sempre in meno. È un'ottimizzazione minore, ma non devi fare affidamento sul compilatore per fare l'ottimizzazione per te.

Inoltre, l'elemento outgoingMassages ..

private ArrayList<OutgoingChatMessage> outgoingMassages .. 

... dovrebbe essere un'interfaccia:

private List<OutgoingChatMessage> outgoingMassages .. 

Poi, chiamando .size() diventerà un metodo virtuale. Per scoprire la classe dell'oggetto specifica, la tabella dei metodi verrà invocata per tutte le classi della gerarchia. Questo non è privo di costi di nuovo.

Problemi correlati