2

I found this StackOverflow post:

Why does Python code run faster in a function?

The short answer for the post's question was "It is faster to store local variables than global ones". So, sometimes it is worth to put loops inside methods.

I have tried to check if this statement could be true for Java and wrote this sample:

public class Main {
    // Global <<iter>> variable:
    public static long ITER = (long) Math.pow(2, 35);

    public static void main(String[] args) {
        // call method from some loop:
        long startTime1 = System.currentTimeMillis();
        // meat 1:
        for (long i = 0; i < Main.ITER; i++){
            long p = Main.ITER;
        }
        // print results:
        long stopTime1 = System.currentTimeMillis();
        long elapsedTime1 = stopTime1 - startTime1;
        System.out.println("Simple loop takes " 
            + elapsedTime1 + " ms to finish.");

        // put method in the loop:
        long startTime2 = System.currentTimeMillis();
        // meat 2:
        myMethod1(Main.ITER);
        // print results:
        long stopTime2 = System.currentTimeMillis();
        long elapsedTime2 = stopTime2 - startTime2;
        System.out.println("Same loop in the method takes " 
            + elapsedTime2 + " ms to finish.");
    }

    public static void myMethod1(long iter) {
        for (long i = 0; i < iter; i++){
            long p = iter;
        }
    }
}

I wanted the code to call Main.ITER multiple times in meat 1 and only once in meat 2 part and then compare milliseconds spent for both. I ran it several times having always the results close to:

Simple loop takes 9199 ms to finish.
Same loop in the method takes 9123 ms to finish.

My JVM (Output from Eclipse installation details):

java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Oracle Corporation
java.vm.specification.version=1.7
java.vm.vendor=Oracle Corporation
java.vm.version=24.80-b11

Here is bytecode for the loop from meat 1 part:

    9 getstatic 20;           /* test6.Main.ITER */
    14 lload_3;               /* i */
    15 lconst_1;
    16 ladd;
    17 lstore_3;              /* i */
    18 lload_3;               /* i */
    19 getstatic 20;          /* test6.Main.ITER */
    22 lcmp;
    23 iflt -14;

Here is bytecode for the loop in the method used in meat 2 part:

    5 lload_0;                /* iter */
    6 lstore 4;
    /* L32 */
    8 lload_2;                /* i */
    9 lconst_1;
    10 ladd;
    11 lstore_2;              /* i */
    12 lload_2;               /* i */
    13 lload_0;               /* iter <- No Main.ITER here ... */
    14 lcmp;
    15 iflt -10;

I am not an expert of Java bytecode, but it seems that myMethod1() doesn't call global variable Main.ITER.

Questions:

  • Is it correct Java implementation for such a test? I might miss some general concepts about how JVM works and optimize this code.
  • Do my results mean that there is no overhead of calling global variables in Java instead of local ones? E.g. it doesn't change the game if I put a loop in some method?

Thank you in advance.

Community
  • 1
  • 1
PMvn
  • 53
  • 7
  • I can totally believe that javac spots that your loop doesn't nothing with `Main.ITER` other than assign the same variable over and over, and just removes the loop. – markspace May 27 '16 at 18:45
  • Thank you for your comment @markspace. If I put these lines `p = p + 2 * 5; String h = "_" + p; h = h + "_";`. It will slow down both `meet 1` and `meet 2` parts - I can conclude that javac doesn't just skip them. But with such a change `meet 1` with global variable call gets 10% - 15% faster. – PMvn May 30 '16 at 10:20

0 Answers0