Проблемы, упомянутые Андреас и непредсказуемость JIT верны, но еще одна проблема связана с загрузчиком классов:
Первый вызов fOne
радикально отличается от последних, потому что это то, что делает первый вызов System.out.println
, что означает, что когда загрузчик классов будет кэшировать с диска или файловой системы (обычно он кэшируется) все классы, которые необходимы для распечатать текст. Укажите параметр -verbose:class
для JVM, чтобы увидеть, сколько классов фактически загружается во время этой небольшой программы.
Я заметил похожее поведение при запуске модульных тестов - первый тест для вызова большого фреймворка занимает гораздо больше времени (в случае с Guice около 250 мс на C2Q6600), хотя тестовый код будет таким же, потому что первый вызов происходит, когда сотни классов загружаются загрузчиком классов.
Поскольку ваша примерная программа такая короткая, накладные расходы, вероятно, связаны с очень ранней оптимизацией JIT и активностью загрузки классов. Сборщик мусора, вероятно, даже не запустится до завершения программы.
Обновление:
Теперь я нашел надежный способ узнать, что действительно занимает время. Этого еще никто не обнаружил, хотя он тесно связан с загрузкой классов — это было динамическое связывание нативных методов!
Я изменил код следующим образом, чтобы журналы показывали, когда тесты начинаются и заканчиваются (просматривая, когда загружаются эти пустые классы маркеров).
TestIO t = new TestIO();
new TestMarker1();
t.fOne();
t.fTwo();
t.fOne();
t.fTwo();
new TestMarker2();
Команда для запуска программы с правильными параметрами JVM, которые показывают что происходит на самом деле:
java -verbose:class -verbose:jni -verbose:gc -XX:+PrintCompilation TestIO
И вывод:
* snip 493 lines *
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Dynamic-linking native method java.lang.ClassLoader.defineClass1 ... JNI]
[Loaded TestIO from file:/D:/DEVEL/Test/classes/]
3 java.lang.String::indexOf (166 bytes)
[Loaded TestMarker1 from file:/D:/DEVEL/Test/classes/]
[Dynamic-linking native method java.io.FileOutputStream.writeBytes ... JNI]
100
Time taken by 'fOne' ... 155354
100
Time taken by 'fTwo' ... 23684
100
Time taken by 'fOne' ... 22672
100
Time taken by 'fTwo' ... 23954
[Loaded TestMarker2 from file:/D:/DEVEL/Test/classes/]
[Loaded java.util.AbstractList$Itr from shared objects file]
[Loaded java.util.IdentityHashMap$KeySet from shared objects file]
* snip 7 lines *
А причина такой разницы во времени вот в чем: [Dynamic-linking native method java.io.FileOutputStream.writeBytes ... JNI]
Мы также видим, что JIT-компилятор не влияет на этот тест. Компилируются только три метода (например, java.lang.String::indexOf
в приведенном выше фрагменте), и все они выполняются до вызова метода fOne
.
person
Community
schedule
29.04.2009