Я заметил кое-что странное при профилировании нашей базы кода. Казалось, что сортировка с типизированным компаратором (например, Comparator
) всегда сначала вызывала метод Comparator
, который затем вызывал метод ] Компаратор
.Более того, большая часть времени была потрачена на Comparator
. Для дальнейшего изучения я сделал небольшую тестовую программу:
public class Sandbox {
public static void main(String argv[]) {
for(int j=0; j<100; j++) {
int n = 10000;
SortMe[] sortMes = new SortMe[n];
for (int i=0; i
Типизированный компаратор:
public class SortMeComp implements Comparator{
public int compare(SortMe one, SortMe two) {
if(one.getValue()>two.getValue()) {
return -1;
} else if (one.getValue()
Нетипизированный компаратор, который я сделал для сравнения:
public class SortMeCompTypeless implements Comparator{
public int compare(Object oneObj, Object twoObj) {
SortMe one = (SortMe) oneObj;
SortMe two = (SortMe) twoObj;
if(one.getValue()>two.getValue()) {
return -1;
} else if (one.getValue()
Вот результаты (из профилировщика YourKit ; дайте мне знать если вы предпочитаете снимок экрана):
+----------------------------------------------------+-----------------+-----------------+--------------------+
| Name | Time (ms) | Own Time (ms) | Invocation Count |
+----------------------------------------------------+-----------------+-----------------+--------------------+
| +---java.util.Arrays.sort(Object[], Comparator) | 23,604 100 % | 8,096 | 200 |
| | | | | |
| +---SortMeComp.compare(Object, Object) | 11,395 48 % | 7,430 | 12,352,936 |
| | | | | | |
| | +---SortMeComp.compare(SortMe, SortMe) | 3,965 17 % | 3,965 | 12,352,936 |
| | | | | |
| +---SortMeCompTypeless.compare(Object, Object) | 4,113 17 % | 4,113 | 12,354,388 |
+----------------------------------------------------+-----------------+-----------------+--------------------+
Я запустил профиль без фильтрации, и вы видите рекурсивные вызовы mergeSort (которые просто затрудняют чтение), но ничего интересного.
Так что здесь происходит? Откуда взялся этот метод SortMeComp.compare (Object, Object)? Мы подумали, что это то, что Java создает внутри себя для работы с дженериками, но что могло занять столько времени? Я бы подумал, что jvm будет просто рассматривать общий метод как «нетипизированный» / Object метод. Как видите, простой заброс намного быстрее. Кроме того, я бы подумал, что это именно та вещь, которую можно было бы убрать с помощью JIT, даже если бы jvm нужно было делать предварительные вещи типа. Что здесь происходит?
Между прочим:
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
Изменить:
В ответ на ответ savinos я попытался смоделировать дополнительный вызов метода с помощью «нетипизированного» компаратора, который просто приводил к типизированному сравнению:
public class SortMeCompMethodCalls implements Comparator{
public int compare(Object oneObj, Object twoObj) {
return compare((SortMe)oneObj, (SortMe)twoObj);
}
public int compare(SortMe one, SortMe two) {
if(one.getValue()>two.getValue()) {
return -1;
} else if (one.getValue()
Вот результаты:
+---------------------------------------------------------+-----------------+-----------------+--------------------+
| Name | Time (ms) | Own Time (ms) | Invocation Count |
+---------------------------------------------------------+-----------------+-----------------+--------------------+
| +---java.util.Arrays.sort(Object[], Comparator) | 31,044 100 % | 8,061 | 200 |
| | | | | |
| +---SortMeComp.compare(Object, Object) | 11,554 37 % | 7,617 | 12,354,392 |
| | | | | | |
| | +---SortMeComp.compare(SortMe, SortMe) | 3,936 13 % | 3,936 | 12,354,392 |
| | | | | |
| +---SortMeCompMethodCalls.compare(Object, Object) | 11,427 37 % | 7,613 | 12,352,146 |
| | | | | |
| +---SortMeCompMethodCalls.compare(SortMe, SortMe) | 3,814 12 % | 3,814 | 12,352,146 |
+---------------------------------------------------------+-----------------+-----------------+--------------------+
Похоже, савинос прав! Дополнительное время - это только дополнительный вызов метода (плюс немного на приведение). Мне это кажется безумным; вы думаете, что это будет JIT прочь? Ах хорошо.
Я удалил редактирование 2 и добавил его как ответ, как и должно было быть изначально.