Ответ 1
Итак, проблема в том, что эти тесты измеряют разные вещи: get()
из населенной карты и remove()
из (в конечном счете) пустой карты. Сравнение бессмысленно, и вы можете выбросить отметку.
Вы должны гарантировать, что операция выполняется против того же HashMap
. К сожалению, это требует либо использования @Setup(Invocation)
, что само по себе плохо (прочитайте Javadoc!), Либо вложите затраты на строительство HashMap
в сам тест:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class HashMapBenchmark {
@Benchmark
public String get() {
HashMap<String, String> hm = createMap();
return hm.get("bye");
}
@Benchmark
public String remove() {
HashMap<String, String> hm = createMap();
return hm.remove("bye");
}
// extra protection from optimization
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
private HashMap<String, String> createMap() {
HashMap<String, String> hm = new HashMap<>();
hm.put("bye", "bye");
return hm;
}
}
Вы можете быть чрезмерно осторожными и очистить создание карты от отдельного не-встроенного метода: сегодня компиляторы не оптимизируют между вызовами. На моем i7-4790K, 4.0 ГГц, Linux x86_64, JDK 8u66:
Benchmark Mode Cnt Score Error Units
HashMapBenchmark.get avgt 15 24.343 ± 0.351 ns/op
HashMapBenchmark.remove avgt 15 24.611 ± 0.369 ns/op
Никакой радикальной разницы. Фактически, если вы посмотрите на сгенерированный код с -prof perfasm
, это даст несколько количественных различий в нем. Или вы можете быстро охарактеризовать обе рабочие нагрузки с помощью -prof perfnorm
.
Обратите внимание, что этот случай не отвечает, лучше ли один метод или другой на реальных картах. Аргумент может быть сделан для обоих: get
не изменяет карту и, следовательно, не создает хранилища памяти, remove
может помочь загрузить факторы, чтобы следующий remove
стал быстрее и т.д. Единый контрольный показатель и параграф текст далеко, далеко от любой плодотворной дискуссии.