Tag Archives: static constructor

Static constructor code is not JIT-optimized in a lot of cases

by Mikhail Vorontsov

I have found this article problem by an accident – I had to initialize a large in-memory static table with results of quite expensive method calls in one of my classes static constructors. Surprisingly, it took much longer than I expected…

Let’s start with a simple test code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private final static int ITERS = 100000000;  //100M
 
private static void test( final String name )
{
    final long start = System.currentTimeMillis();
    long res = start;
    for ( int i = 0; i < ITERS; ++i )
    {
        for ( int j = 0; j < 20; ++j )
            res = add2( res,  sub( add( i, j ), 1 ) );
    }
    final long time = System.currentTimeMillis() - start;
    System.out.println( name + ": Time = " + time / 1000.0 + " sec, res = " + res );
}
 
public static int add( final int a, final int b )
{
    return a + b;
}
 
public static int sub( final int a, final int b )
{
    return a - b;
}
 
public static long add2( final long a, final int b )
{
    return a + b;
}
private final static int ITERS = 100000000;  //100M

private static void test( final String name )
{
    final long start = System.currentTimeMillis();
    long res = start;
    for ( int i = 0; i < ITERS; ++i )
    {
        for ( int j = 0; j < 20; ++j )
            res = add2( res,  sub( add( i, j ), 1 ) );
    }
    final long time = System.currentTimeMillis() - start;
    System.out.println( name + ": Time = " + time / 1000.0 + " sec, res = " + res );
}

public static int add( final int a, final int b )
{
    return a + b;
}

public static int sub( final int a, final int b )
{
    return a - b;
}

public static long add2( final long a, final int b )
{
    return a + b;
}

We have 4 billion additions and 2 billion subtractions to execute. How long should it take on a modern CPU? We could expect something close to number of operations / CPU frequency (all these operations could be executed on registers only, without any memory access) – something in between 1.5 and 4 seconds.

Initially we will define these methods in the same class with static constructor and call test method in a static constructor in a loop in order to trigger JIT-compilation. Surprisingly, it took 46 seconds to run test method a single time on my Core i5-3317 (1.7Ghz). At least 10 times slower than we may expect. And it took the same time for subsequent calls (I made 30 of them). Something is very wrong, I thought… Was my code actually JIT-compiled? I’ve added -XX:+PrintCompilation Java option – it printed that yes, my methods were compiled:

Continue reading