One small optimization

    Most recently, they shared with me the story of an optimization (hello stanislaw ), which seemed pretty funny to me.

    A game project and with an ever-growing user base, but since I didn’t want to expand in breadth, the task arose to optimize the existing code in bottlenecks. After a short profiling, literally right away, I managed to find one such bottleneck that, at first glance, would not have caused anyone to suspect:

    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 story. There is a certain method of calculating the situation on the map, in which there are many iterations over various kinds of cycles. Moreover, the graph of objects has already been created and only its state is changing. 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 quite a large part of the method’s time.

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

    for (Iterator i = arrayListA.iterator(); i.hasNext();) {
        a = i.next();
    }
    //смотрим во внутрь метода iterator() ArrayList
    public Iterator iterator() {
        return new Itr();
    }
    //и сам класс итератора. поля которые потребляют память
    private class Itr implements Iterator {
    	int cursor = 0;
    	int lastRet = -1;
    	int expectedModCount = modCount;
    }
    

    Everything would be fine, but if you have several nested loops, and short loops at the lowest level of nesting, it turns out that just a single loop through the loops will create thousands of objects, and if the method is constantly called, then the collector will constantly fire.
    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 a single loop ...

    Solution here it’s pretty obvious to get access by index:

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


    Such a small code change in this particular case allowed to increase the speed of the hot method by 2 times.
    It is worth noting that this kind of optimization is possible mainly in the case of ArrayList.

    Be careful and happy New Year!

    Also popular now: