Java-сортировка с помощью Comparator большую часть времени тратит на сравнение (Object, Object)

Я заметил кое-что странное при профилировании нашей базы кода. Казалось, что сортировка с типизированным компаратором (например, Comparator ) всегда сначала вызывала метод Comparator .compare (Object, Object) , который затем вызывал метод ] Компаратор .compare (MyClass, MyClass) .Более того, большая часть времени была потрачена на Comparator .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

Типизированный компаратор:

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 и добавил его как ответ, как и должно было быть изначально.

14
задан Bryan Head 15 April 2014 в 16:45
поделиться