Avoid indirect and redundant method calls

I am currently browsing a PullRequest which contains the following:

- 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

somehow it seems awkward to me - I would think that vm does these optimizations - but it cannot be said for sure. I would like to get some input if this change might make sense - or confirmation that this is being done on the VM side.

+5
source share
5 answers

No, not sure if the virtual machine will change your code with

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

to

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

In your for loop, it is possible that outgoingMassages will resize. Therefore, this optimization cannot be applied by the JVM. Also, another thread may resize outgoingMassages if it is a shared resource.

JVM can change the code only if the behavior does not change. For example, it can replace the string concatenation list with the sequence of addition to the StringBuilder or it can embed a simple method call, or it can calculate a value from a loop if it is a constant value.

+5
source

VM will not do this optimization. Since it is possible that the size () method does not return the same result to every call. Therefore, the method should be called each iteration.

However, if size is a simple getter method, the performance impact is very small. It is probably impossible to measure. (In a few cases, this may allow Java to use parallelization, which may matter then, but it depends on the contents of the loop).

A larger difference may be to ensure that the for-loop has the number of iterations that is known in advance. In this example, it seems to me impractical. But maybe the called method can return modified results that are undesirable?

+1
source

If the size() method in your collection simply gives the value of a private field, then the virtual machine will optimize most of this (but not all). He will do this by introducing the size() method so that it simply becomes available for this field.

The remaining bit, which will not be optimized, is that size in the new code will be processed as final and, therefore, constant, while the field taken from the collection will not be considered final (it may have been changed from another thread). Thus, in the original case, the field will be read at each iteration, but in the new case it will not.

0
source

Probably any decent optimizer - either in a virtual machine or in a compiler - will recognize:

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

and optimize it to

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

Performing extra-unchecked optimization should be considered evil .

0
source

A method call will be executed in each iteration of the loop and is not a free cost. Since you cannot predict how often this happens, calling it once is always less . This is a small optimization, but you should not rely on the compiler to optimize for you.

Next, the outgoingMassages member ..

 private ArrayList<OutgoingChatMessage> outgoingMassages .. 

... there should be an interface:

 private List<OutgoingChatMessage> outgoingMassages .. 

Then calling .size() will become a virtual method. To find out a specific class of an object, a method table will be called for all classes in the hierarchy. This again is not exempt from costs.

0
source

Source: https://habr.com/ru/post/1232966/


All Articles