2010-05-18 3 views
16

Je me demandais, est la méthode size() que vous pouvez appeler sur un ArrayList<T> existant en cache? Ou est-ce préférable dans le code critique de performance que je viens de stocker le size() dans un int local?La méthode ArrayList.size() est-elle mise en cache?

Je m'attendrais à ce qu'il soit effectivement mis en cache, lorsque vous n'ajoutez/ne supprimez pas d'éléments entre les appels à size().

Ai-je raison?

mise à jour
Je ne parle pas de inline ou de telles choses. Je veux juste savoir si la méthode size() elle-même met en cache la valeur en interne, ou qu'elle calcule dynamiquement chaque fois qu'elle est appelée.

+0

Il est un appel rapide pour ArrayList, mais stocker le résultat dans la variable locale si vous l'utilisez comme un test condition dans chaque itération de la boucle. –

+1

pouvez-vous s'il vous plaît clarifier la question. Il semble que certaines personnes interprètent cela comme "fait size() effectue un calcul ou retourne trivialement un champ" vs. "plusieurs appels à size() seront remplacés par un seul appel à size() avec les invocations suivantes remplacées par une variable locale dans laquelle le résultat précédent a été sauvegardé ". J'ai interprété comme le dernier, tandis que d'autres ont interprété comme le premier. S'il vous plaît, faites cela complètement clair. –

+0

Merci pour la clarification. –

Répondre

11

Je ne pense pas que je dirais que c'est "mis en cache" en tant que tel - mais il est simplement stocké dans un champ, il est donc assez rapide pour appeler fréquemment.

La mise en œuvre de Sun JDK size() est juste:

public int size() { 
    return size; 
} 
+0

@Jon, mais dans le code critique de performance, cela paye beaucoup pour le coût de l'appel de fonction, quand la valeur sera la même. –

+6

@Michael mais le JIT est assez intelligent pour mettre en ligne de tels appels, donc vous n'avez pas le temps d'appel de la fonction. – Jesper

+1

@Jesper - J'apprécie qu'il soit théoriquement possible d'intégrer l'appel, mais quelle VM fait-il cela? – msandiford

0

L'implémentation évidente de ArrayList consisterait à stocker la taille en interne dans un champ. Je serais très surpris si jamais il devait être calculé, même après le redimensionnement.

0

Pourquoi aurait-il besoin d'être? ArrayList implémente une interface List qui est sauvegardée par un tableau, après tout.

Je suppose à juste un membre size, qui est incrémentée lorsque vous insérez des choses et décrémenté lorsque vous retirez, puis il retourne exactement cela.

Je n'ai pas regardé plus que les docs d'API maintenant, cependant.

+0

car l'en-tête d'invocation de fonction est non-négligeable. Vous payez beaucoup juste pour être renvoyé la valeur d'un champ. Si elle est appelée encore et encore dans une boucle, vous pouvez obtenir des économies en éliminant l'appel. –

+0

@Michael le JIT est assez intelligent pour intégrer de telles méthodes simples, alors vous n'avez pas la surcharge d'appel de fonction. – Jesper

+0

@Michael: Bien sûr, mais ce n'était pas la question. La question était de savoir si ArrayList * met en cache * la taille, de sorte que size() peut simplement renvoyer une valeur mise en cache plutôt que de la recalculer. Ma réponse tente d'expliquer qu'il n'y a probablement rien à calculer, et d'autres semblent le confirmer après avoir vérifié la source. Cela n'a rien à voir avec la surcharge de l'appel de méthode. – unwind

2

Je ne connais pas la réponse sûre, mais je pense serait: non. Il n'y a aucun moyen pour un compilateur Java, à moins de spécial ArrayList, de savoir que les fonctions que vous appelez seront non-mutantes et que, par conséquent, l'appel de size() devrait retourner la même valeur. Par conséquent, je trouve très improbable qu'un compilateur Java factorise les appels répétés à size() et les stocke dans une valeur temporaire. Si vous avez besoin de ce niveau d'optimisation, vous devriez stocker vous-même la valeur dans une variable locale. Sinon, oui, vous paierez le coût d'invocation de la fonction associé à l'appel de la méthode size(). Notez, cependant, que la méthode size() est O (1) pour une ArrayList (bien que la surcharge de l'appel de fonction soit assez lourde). Personnellement, j'élimine tous les appels à size() des boucles et les stocke manuellement dans un local, le cas échéant.

Modifier
Même si une telle optimisation ne peut être effectuée par un compilateur Java, il a été bien souligné que le JIT peut inline la mise en œuvre de ArrayList.size() de telle sorte qu'il ne coûte que même en tant que Les coûts sont négligeables, bien que vous puissiez économiser légèrement en enregistrant manuellement dans un fichier temporaire (ce qui pourrait potentiellement éliminer une recherche de mémoire et servir à la place la variable dans un registre CPU).

+0

Pourquoi le downvote? –

+0

Vraisemblablement parce que votre réponse est factuellement inexacte - 'size()' retourne effectivement sans effectuer de calculs supplémentaires, et le code sait quelles implémentations de méthodes modifient la taille et lesquelles ne le font pas. Votre discussion sur les compilateurs est un faux-fuyant, elle est implémentée au niveau du code source et est très simple. En outre, dire que vous ne connaissez pas la réponse à coup sûr (quand cela prendrait deux minutes à vérifier) ​​et répondre de toute façon n'est pas très utile. –

+0

@Michael - Je suppose que c'est parce que tout le monde interprète la question comme "est la valeur stockée en interne ou calculée chaque fois" et vous l'interprétez comme "vous devrez appeler la méthode à chaque fois ou la valeur est stockée dans un registre après le premier appel. " – tvanfosson

4

Oui. Un rapide coup d'oeil à la source Java vous dira la réponse.

+0

@Tim, esprit indiquant où dans le code c'est? –

+0

@Michael - Dans le fichier 'src.zip' de votre répertoire d'installation JDK. – Jesper

+0

Désolé! J'ai fait des suppositions - je garde généralement l'accès à la source JDK à partir de mon IDE. Merci pour la main, Jesper. – Timothy

2

C'est la mise en œuvre OpenJDK version:

/** 
* Returns the number of elements in this list. 
* 
* @return the number of elements in this list 
*/ 
public int size() { 
    return size; 
} 

Il est aussi bon que un appel de méthode va obtenir. Il n'est pas très probable que HotSpot met en cache la valeur retournée par cette méthode, donc si vous êtes vraiment , vous pouvez le mettre en cache vous-même. À moins que votre profilage ait montré qu'il s'agit d'un goulot d'étranglement, mais pas très probable, vous devriez simplement vous soucier de la lisibilité plutôt que de savoir si un simple appel de méthode qui renvoie la valeur d'un champ est mis en cache ou non.

0

Si la mise en cache le résultat de la méthode size() serait sensiblement améliorer les performances (ce qui ne parfois - je vois régulièrement ArrayList.size() en haut méthode compilée dans ma -Xprof sortie) puis envisager de convertir toute la liste à un tableau pour une accélération encore plus .

est ici un truc qui peut fonctionner si vous itérer sur la liste régulièrement mais seulement mettre à jour rarement:

class FooProcessor { 

    private Foo[] fooArray = null; 
    private List<Foo> fooList = new ArrayList<Foo>(); 

    public void addFoo(Foo foo) { 
     fooList.add(foo); 
     fooArray = null; 
    } 

    public void processAllFoos() { 
     Foo[] foos = getFooArray(); 
     for (int i = 0; i < foos.length; ++ i) { 
      process(foos[i]); 
     } 
    } 

    private void getFooArray() { 
     if (fooArray == null) { 
      Foo[] tmpArray = new Foo[fooList.size()]; 
      fooArray = fooList.toArray(tmpArray); 
     } 
     return fooArray; 
    } 

}