2010-07-29 20 views
2

Je suis curieux de savoir si l'une de ces deux invocations de méthode Java se comportera différemment en termes de temps de processeur, d'allocation de mémoire et/ou de garbage collection.Une différence dans les performances de ces deux segments Java?

SomeObject myObj = new SomeObject(); 
myObj.doSomething(); 

contre

new SomeObject().doSomething(); 
+0

J'espère que vous ne créerez pas souvent un objet seulement pour appeler une seule méthode dessus. Ou de s'inquiéter de cette performance. –

+0

@Tom: Pourquoi cela serait-il mauvais? S'il a seulement besoin d'exécuter la méthode unique et qu'il en a fini avec ça, alors, eh bien, c'est tout ce qu'il doit faire. Comme, "nouveau Logger() .écrire (" Panic! Abort! Nous allons vers le bas! ");" Nous n'utilisons pas le journal agan. Quant à la différence de performance, pour un appel, je suis sûr que c'est trivial. Mais ces choses s'additionnent. Une nanoseconde économisée est une nanoseconde gagnée. – Jay

+0

Pas souvent. Il est venu de générer un nouveau thread dans une application Android. – iandisme

Répondre

5

En regardant le bytecode généré:

// code 1 
new SomeObject().doSomething(); 

// bytecode 1 
    0: new #2; //class SomeObject 
    3: dup 
    4: invokespecial #3; //Method SomeObject."<init>":()V 
    7: invokevirtual #4; //Method SomeObject.doSomething:()V 
    10: return 

Vous pouvez clairement voir que celui-ci a deux instructions:

// code 2 
SomeObject myObj = new SomeObject(); 
myObj.doSomething(); 

// bytecode 2 
    0: new #2; //class SomeObject 
    3: dup 
    4: invokespecial #3; //Method SomeObject."<init>":()V 
    7: astore_1 
    8: aload_1 
    9: invokevirtual #4; //Method SomeObject.doSomething:()V 
    12: return 

Ces instructions semblent très redondantes et faciles à optimiser-out. Je parierais que le compilateur JIT les manipulerait si nécessaire.

+0

C'est à peu près dans le sens de ce que j'attendais. Merci d'être moins paresseux que moi et de poster le code d'octet! – iandisme

2

n °        

+1

Ha - Je m'attendais à celui-ci. – iandisme

1

En supposant que myObj ne soit pas utilisé pour autre chose, comme je déduire de la nature de votre question, vous ne devrait voir aucune différence. D'une manière ou d'une autre, la seule fois où vous devriez vous inquiéter de l'overhead comme ceci serait si ce code est dans une boucle qui l'exécute encore et encore, ad nauseum. Si tel est le cas, l'optimisation JIT de Java devrait prendre très bien soin de vous et vous ne devriez voir aucune différence. Je préfère voir ce code écrit comme votre deuxième exemple, mais c'est juste moi.

+0

Je préfère plutôt la variante 1 car elle facilite le débogage. Il y a un appel de méthode dans chaque ligne, donc vous pouvez décider pour chaque méthode si vous voulez intervenir ou l'ignorer. De cette façon, vous pouvez également examiner les résultats intermédiaires des algorithmes pour vérifier s'ils ont la valeur attendue. Cela est particulièrement important lorsque l'appel des méthodes produit des effets secondaires indésirables. –

0

La seule différence entre les deux est que tant que la référence myObj n'est pas effacée et qu'une partie d'un objet ayant un path to root l'objet alloué ne sera pas récupérée.

4

La différence est exactement 2 bytecodes JVM, ce qui se traduit par 1 instruction machine supplémentaire, que le JIT peut optimiser (si vous ne faites rien d'autre avec la variable).

+0

Si c'était une chose sensée à prendre en compte, une traduction naïve en code machine introduirait typiquement deux instructions (stocker dans une trame locale, suivies d'une charge de la même) - identiques aux bytecodes. –

+0

Nop, le compilateur peut réutiliser la valeur immédiatement, soit dans un registre ou sur la pile (en ignorant les variables volatiles pour le moment). javac mettra 2 instructions (un magasin, une charge) en raison de la sémantique. –

1

Bien que le bytecode généré puisse être différent, je pense que cela devrait être l'une des choses les plus faciles à optimiser pour un compilateur jit. En fonction de ce qu'il fait réellement, même la création d'objet pourrait être entièrement optimisée.

0

Le premier exemple sera légèrement moins efficace. Dans le premier exemple, la référence d'objet sera conservée jusqu'à la fin de la fonction ou du bloc englobant. Dans le deuxième exemple, la référence d'objet sera disponible pour la récupération de place une fois l'appel terminé. Bien sûr, il peut ne pas être effectivement ramassé.

Je n'ai pas vérifié le bytecode généré. Il y a probablement une différence dans la façon dont Java contient la référence, mais dans les deux cas, je pense que c'est trivial.