Медленная компиляция JDK8

При попытке перейти на JDK8 в большом проекте компиляция на JDK8 идет очень медленно по сравнению с JDK7.

Запуская компилятор в подробном режиме, компилятор JDK8 останавливается на большом сгенерированном классе конвертера (Mapping) для сущностей от сервера к клиенту. Методы конвертера в некоторых случаях вызывают другие методы конвертера из того же класса Mapping.

В качестве обходного пути попытался разбить файл сопоставления на несколько файлов. Это заметно улучшило производительность при компиляции только класса Mapping или содержащего его проекта (projectA). Но время компиляции было очень медленным для других проектов, которые вызывают методы конвертера из projectA.

Другим обходным решением было заставить все методы преобразования возвращать ноль, не вызывая ничего другого. Опять же, производительность была хорошей для projectA, но не для зависимых проектов.

ProjectA использует дженерики, но, поскольку он совместим с JDK6, в котором не было введено обобщенного вывода типов, возможно, это еще одна ошибка JDK8, которая вызывает это замедление.

Поэтому, возможно, вне контекста, но для обобщенного вывода типов, некоторые потоки, подобные приведенным ниже, предлагают обновление до JDK9. Но так как он еще не выпущен, он не подходит для обновления. Было бы идеально, если бы бэкпорт исправления был сделан для JDK8. Это было запрошено в следующем потоке Stackru, но ответа от команды Oracle пока нет.

Медленная компиляция с jOOQ 3.6+, простым SQL и компилятором javac

Я приложил 2 скриншота того, как выглядит куча в JDK7 против JDK8. Может ли это быть причиной замедления JDK8?

Спасибо!

Обновление 20160314

Методы конвертера из класса Mapping выглядят так:

public static ResponseItemVO convert (ResponseItem pArg0){
         if(pArg0==null){
             return null;
         }
        ResponseItemVO ret = new ResponseItemVO();
        ret.setErrorDetails(pArg0.getErrorDetails());
        ret.setResult(Mapping.convert(pArg0.getResult()));
        ret.setIdentifier(Mapping.convert(pArg0.getIdentifier()));
        return ret;
    }

И экшн выглядит так:

public class ResponseItemVO extends ResultVO<IdentifierVO, DetailsVO >  {
    public ResponseItemVO() {}
}

JDK7 куча: JDK7-вороха Куча JDK8: JDK8-вороха

1 ответ

Решение

Вы уже заметили, что в Java 8 наблюдается серьезное снижение производительности, когда речь идет о разрешении перегрузки, основанном на типовой типизации. Одной из причин в вашем случае может быть тот факт, что компилятор должен найти соответствующий метод из типа присваивания

ResultVO<Something, Something> result = Mapping.convert(...);
// heavy lookup here ---------------------------^^^^^^^

Если вы контролируете генератор кода и не ограничены обратной совместимостью, возможно, стоит подумать об избежании перегрузки convert() метод. Без перегрузки компилятору не нужно выполнять работу по разрешению перегрузки ни внутри кода отображения, ни на сайте вызовов. Это, безусловно, будет намного быстрее.

Попытка 1: с помощью типа параметра в имени метода:

class Mapping {
    public static ResponseItemVO convertResponseItem(ResponseItem pArg0){
        if (pArg0==null){
            return null;
        }
        ResponseItemVO ret = new ResponseItemVO();
        ret.setErrorDetails(pArg0.getErrorDetails());
        ret.setResult(Mapping.convertResult(pArg0.getResult()));
        ret.setIdentifier(Mapping.convertIdentifier(pArg0.getIdentifier()));
        return ret;
    }
}

Попытка 2: перемещая метод convert в другое место, например, в VO тип

class ResponseItemVO {
    public static ResponseItemVO from(ResponseItem pArg0){
        if (pArg0==null){
            return null;
        }
        ResponseItemVO ret = new ResponseItemVO();
        ret.setErrorDetails(pArg0.getErrorDetails());
        ret.setResult(ResultVO.from(pArg0.getResult()));
        ret.setIdentifier(IdentifierVO.from(pArg0.getIdentifier()));
        return ret;
    }
}

Или лучше...

class ResponseItem {
    public ResponseItemVO toVO(){
        ResponseItemVO ret = new ResponseItemVO();
        ret.setErrorDetails(getErrorDetails());
        ret.setResult(getResult().toVO());
        ret.setIdentifier(getIdentifier().toVO());
        return ret;
    }
}
Другие вопросы по тегам