Первый раз цикл Java запускается МЕДЛЕННО, почему? [Sun HotSpot 1.5, sparc]

При тестировании некоторого Java-кода на блоке Solaris SPARC я заметил, что при первом вызове тестируемой функции она запускается ОЧЕНЬ медленно (разница в 10 раз):

Первый | 1 | 25295,979 мсВторой | 1 | 2256,999 мсТретий | 1 | 2250,575 мс

Почему это? Я подозреваю, что JIT-компилятор, есть ли способ проверить это?

Редактировать: В свете некоторых ответов я хотел бы уточнить, что этот код - самый простой возможный тестовый пример, который я мог найти, демонстрируя такое поведение. Поэтому моя цель не в том, чтобы заставить его работать быстро, а в том, чтобы понять, что происходит, чтобы я мог избежать этого в моих реальных тестах.

Решено: Том Хотин правильно указал, что мое «МЕДЛЕННОЕ» время было действительно разумным. После этого наблюдения я подключил отладчик к процессу Java. Во время первого, внутренний цикл выглядит так:

0xf9037218:     cmp      %l0, 100
0xf903721c:     bge,pn   %icc,0xf90371f4        ! 0xf90371f4
0xf9037220:     nop
0xf9037224:     ld       [%l3 + 92], %l2
0xf9037228:     ld       [%l2 + 8], %l6
0xf903722c:     add      %l6, 1, %l5
0xf9037230:     st       %l5, [%l2 + 8]
0xf9037234:     inc      %l0
0xf9037238:     ld       [%l1], %g0
0xf903723c:     ba,pt    %icc,0xf9037218        ! 0xf9037218

На следующих итерациях цикл выглядит так:

0xf90377d4:     sub      %l2, %l0, %l3
0xf90377d8:     add      %l3, %l0, %l2
0xf90377dc:     add      %l2, 1, %l4
0xf90377e0:     inc      %l0
0xf90377e4:     cmp      %l0, 100
0xf90377e8:     bl,pn    %icc,0xf90377d8        ! 0xf90377d8

Таким образом, HotSpot удалил доступ к памяти из внутреннего цикла, ускорив его на порядок.

Урок: Делать математику! Я должен был сделать расчет Тома сам.

Тестовый Java-код:

    private int counter;
    private int nThreads;

    private void measure(String tag) throws Exception {
            MyThread threads[] = new MyThread[nThreads];
            int i;

            counter = 0;

            for (i = 0; i < nThreads; i++)
                    threads[i] = new MyThread();

            long start = System.nanoTime();

            for (i = 0; i < nThreads; i++)
                    threads[i].start();

            for (i = 0; i < nThreads; i++)
                    threads[i].join();

            if (tag != null)
                    System.out.format("%-20s | %-2d | %.3f ms \n", tag, nThreads,
                                     new Double((System.nanoTime() - start) / 1000000.0));
    }
    public MyBench() {
            try {
                    this.nThreads = 1;
                    measure("First");
                    measure("Second");
                    measure("Third");
            } catch (Exception e) {
                    System.out.println("Error: " + e);
            }
    }

    private class MyThread extends Thread {
            public void run() {
                    while (counter < 10000000) {
                            // work
                            for (int j = 0; j < 100; j++)
                                    counter++;
                            counter -= 99;
                    }
            }
    }

Ответы на вопрос(7)

Ваш ответ на вопрос