Это классическая проблема бенчмаркинга Java. Hotspot / JIT / etc будет компилировать ваш код во время его использования, поэтому он будет быстрее во время выполнения.
Сначала запустите цикл по крайней мере 3000 раз (10000 на сервере или на 64-битной основе) - затем сделайте свои измерения.
Скорее всего, код все еще компилировался или еще не скомпилирован в момент запуска первого цикла.
Оберните весь метод во внешнем цикле, чтобы несколько раз запустить тесты, и вы должен видеть более стабильные результаты.
Чтение: Динамическое компиляция и измерение производительности .
Вы знаете, что что-то не так, потому что Bytes.toBytes
вызывает c.getBytes
внутренне:
public static byte[] toBytes(String s) {
try {
return s.getBytes(HConstants.UTF8_ENCODING);
} catch (UnsupportedEncodingException e) {
LOG.error("UTF-8 not supported?", e);
return null;
}
}
Источник берётся из здесь . Это говорит о том, что вызов не может быть быстрее, чем прямой вызов - в лучшем случае (т. Е. Если он встанет в очередь) он будет иметь одинаковые сроки. В общем, вы ожидаете, что это будет немного медленнее из-за небольших накладных расходов при вызове функции.
Это классическая проблема с микро-бенчмаркингом в интерпретируемых средах с мусором с компонентами которые выполняются в произвольное время, например сборщики мусора. Кроме того, существуют аппаратные оптимизации, такие как кеширование, которые искажают изображение. В результате лучший способ увидеть, что происходит, - это часто смотреть на источник.
Bytes.toBytes()
вызывает c.getBytes("UFT-8")
внутренне, но с кодировкой в качестве входа. String
s getByte()
имеет немного накладных расходов, чем getByte("UTF-8")
и, следовательно, медленнее. Короче Bytes.toBytes()
работает быстрее.
– Santosh
18 December 2013 в 15:46
«Второй» цикл выполняется быстрее, поэтому
blockquote>Когда вы выполняете метод не менее 10000 раз, он запускает весь метод для компиляции. Это означает, что ваш второй цикл может быть
- быстрее, поскольку он уже скомпилирован при первом запуске.
- медленнее, потому что при оптимизации он не имеет хорошей информации / счетчик о том, как выполняется код.
Лучшее решение состоит в том, чтобы поместить каждый цикл в отдельный метод, чтобы один цикл не оптимизировал другой И запустил это несколько раз, игнорируя первый
, например
for(int i = 0; i < 3; i++) { long time1 = doTest1(); // timed using System.nanoTime(); long time2 = doTest2(); System.out.printf("Test1 took %,d on average, Test2 took %,d on average%n", time1/RUNS, time2/RUNS); }
Просто может быть так, что вы выделяете столько объектов для объектов с вашими вызовами getBytes (), что запускает сборщик мусора JVM и очищает неиспользуемые ссылки (выводя мусор).
Немногие другие наблюдения
Bytes.toBytes(c);
внутренне вызывает String.getBytes("UTF-8")
String.getBytes()
, который принимает набор символов поскольку входной сигнал быстрее, чем тот, который не принимает никакого набора символов. Поэтому для данной строки getBytes("UTF-8")
будет быстрее, чем getBytes()
. Я тестировал это на своей машине (Windows8, JDK 7). Выполните две петли, одна с getBytes("UTF-8")
и другая с getBytes()
последовательно в равных итерациях. long ts;
String c = "sgfrt34tdfg34";
ts = System.currentTimeMillis();
for (int k = 0; k < 10000000; k++) {
c.getBytes("UTF-8");
}
System.out.println("t1->" + (System.currentTimeMillis() - ts));
ts = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
c.getBytes();
}
System.out.println("t2->" + (System.currentTimeMillis() - ts));
это дает:
t1->1970
t2->2541
, и результаты одинаковы, даже если вы меняете порядок выполнения цикла. Чтобы уклониться от любых оптимизаций JIT, я бы предложил запустить тесты по отдельным методам, чтобы подтвердить это (как это предложил @Peter Lawrey выше)
Bytes.toBytes(c)
всегда будет быстрее, чем String.getBytes()