Я заметил кое-что странное во время профилирования нашей базы кода.Казалось, что сортировка с типизированным компаратором (например, Comparator<MyClass>
) всегда сначала вызывала метод Comparator<MyClass>.compare(Object,Object)
, который затем вызывал метод Comparator<MyClass>.compare(MyClass,MyClass)
.Кроме того, подавляющее большинство времени было потрачено на Comparator<MyClass>.compare(Object,Object)
.Для дальнейшего изучения я создал небольшую тестовую программу:
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<n; i++) {
sortMes[i] = new SortMe(Math.random());
}
Arrays.sort(sortMes, new SortMeComp());
System.out.println(Arrays.toString(sortMes));
}
for(int j=0; j<100; j++) {
int n = 10000;
SortMe[] sortMes = new SortMe[n];
for (int i=0; i<n; i++) {
sortMes[i] = new SortMe(Math.random());
}
Arrays.sort(sortMes, new SortMeCompTypeless());
System.out.println(Arrays.toString(sortMes));
}
}
}
Типизированный компаратор:
public class SortMeComp implements Comparator<SortMe>{
public int compare(SortMe one, SortMe two) {
if(one.getValue()>two.getValue()) {
return -1;
} else if (one.getValue()<two.getValue()) {
return 1;
} else {
return 0;
}
}
}
Нетипизированный компаратор, который я создал для сравнения:
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()<two.getValue()) {
return 1;
} else {
return 0;
}
}
}
Вот результаты (из YourKit profiler ; дайте мне знать, если у вас есть скриншот):
+----------------------------------------------------+-----------------+-----------------+--------------------+
| 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 |
+----------------------------------------------------+-----------------+-----------------+--------------------+
Я запустил профиль без фильтрации, и вы видите рекурсивные вызовыобъединить сортировку (которая просто затрудняет чтение), но ничего интересного.
Так что здесь происходит?Откуда этот метод SortMeComp.compare (Object, Object)?Мы полагали, что это что-то, что Java создает внутри для работы с дженериками, но что может занять так много времени?Я бы подумал, что jvm будет рассматривать общий метод как «нетипизированный» метод / Object.Как видите, простое приведение гораздо быстрее.Кроме того, я думаю, что это именно та вещь, которая будет JITED, даже если 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()<two.getValue()) {
return 1;
} else {
return 0;
}
}
}
Вот результаты:
+---------------------------------------------------------+-----------------+-----------------+--------------------+
| 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 JED далеко?Ах, хорошо.
Я удалил редактирование 2 и добавил его в качестве ответа, как и должно было быть изначально.