📜 ⬆️ ⬇️

One small optimization

More recently, I was told a story of one optimization (hello stanislaw ), which seemed to me rather amusing.

The project is game-based and with an ever-growing user base, but since it did not want to expand to the breadth, there was a task to optimize the existing code in narrow places. After a brief profiling, literally immediately, we managed to find one such bottleneck, which at first glance would not cause anyone suspicion:

for (A a : arrayListA) { // do something for (B b : arrayListB) { // do something for (C c : arrayListC) { // do something } } } 

I do not have access to the code, so I only convey the essence of the narration. There is a certain method of miscalculation of the situation on the map, in which there are many iterations on all sorts of cycles. Moreover, the object graph has already been created and only its state changes. That is, new objects are not actually created ... But nevertheless, the profiler showed approximately the following picture (picture from the previous topic):
')
image

And with frequent calls to the method, the assembly took up quite a large part of the time the method worked.

The problem was in for loops. As you know, the compiler converts the for loop for collections into the following code:

 for (Iterator<A> i = arrayListA.iterator(); i.hasNext();) { a = i.next(); } //    iterator() ArrayList public Iterator<E> iterator() { return new Itr(); } //   .     private class Itr implements Iterator<E> { int cursor = 0; int lastRet = -1; int expectedModCount = modCount; } 

Everything would be fine, but if you have several nested loops, with short cycles at the lowest level of nesting, it turns out that just a single walk through the cycles will create thousands of objects, and if the method is constantly invoked, then the collector will always trigger.
For example, for the first example, if arrayListA.size () == 1000, arrayListB.size () == 100, arrayListC.size () == 10, about 100 thousand iterator objects will be created in one pass through the cycles ...

The solution here is pretty obvious - get access to the index:

 for (int i = 0; i < arrayListA.size(); i++) { A a = arrayListA.get(i); } 


Such a small code change in this particular case made it possible to increase the speed of the hot method by 2 times.
It should be noted that this kind of optimization is possible mainly in the case of ArrayList.

Be attentive with the New Year past you!

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


All Articles