Apache POI 4.0.1 очень медленно начинает работу ... 15 минут или больше. Что случилось? - PullRequest
0 голосов
/ 14 января 2019

Для POI требуется 15 минут или более, чтобы инициализировать свою первую книгу на Java 8 в Windows 10 в экземпляре Tomcat 8. Основываясь на прерывании процесса в отладчике и просмотре стека, он проводит время в загрузчике классов, управляемом xbeans.

Редактировать Это похоже на проблему загрузчика классов, потому что когда я реализовал обходной путь для библиотеки POI (ниже), другие классы начали выражать ту же проблему.

Редактировать Трассировка стека наиболее похожа на эту ошибку: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8022063

Как вы можете видеть в jvisualvm, в потоке процессов taskExecutor-1 нет конфликта загрузчика классов.

jvisualvm screenshot showing affected process

У меня есть обходной путь, но он не должен быть необходим. Принятый ответ объяснит ПОЧЕМУ это происходит.

РЕДАКТИРОВАТЬ: Обходной путь

Во время инициализации приложения я добавил эту строку в инициализатор статического класса для bean-компонента конфигурации, чтобы заставить загрузчик классов предварительно загружать классы и ресурсы. Там он выполняется мгновенно, а когда вызывается реальный процесс, он также запускается мгновенно.

XSSFWorkbook preload = new XSSFWorkbook ();

Последний обходной путь - предварительная загрузка всех jar-файлов, связанных с SSL, безопасностью и POI. Насколько я могу судить, при поздней загрузке в контексте весеннего пакета (может быть красная сельдь) загрузчик классов пытается проверить файлы jar bouncycastle с помощью алгоритмов, закодированных в классах bouncycastle, и выполняет все в стеке SSL в интерпретируемый режим.

        Reflections reflections = new Reflections("org.bouncycastle", this.getClass().getClassLoader(), new SubTypesScanner(false));
        Set<Class<? extends Object>> bouncyCastleClasses = reflections.getSubTypesOf(Object.class);



        reflections = new Reflections("sun.security", this.getClass().getClassLoader(), new SubTypesScanner(false));
        Set<Class<? extends Object>> sunSecurityClasses = reflections.getSubTypesOf(Object.class);

        reflections = new Reflections("javax.ssl", this.getClass().getClassLoader(), new SubTypesScanner(false));
        Set<Class<? extends Object>> javaSslClasses = reflections.getSubTypesOf(Object.class);

        reflections = new Reflections("org.apache.poi", this.getClass().getClassLoader(), new SubTypesScanner(false));
        Set<Class<? extends Object>> poiClasses = reflections.getSubTypesOf(Object.class);

выдержка из POM:

    <poi.version>4.0.1</poi.version>

        <!-- apache poi / poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>

Код:

public void beforeJob(JobExecution jobExecution) {
    if (logger.isDebugEnabled()) {
        workbookname = "debuginfo-" + System.currentTimeMillis() + ".xlsx";
        logger.debug("Debug statistics dump file will be saved at [{}]", workbookname);
        debugStatsDump = new XSSFWorkbook(); // This line takes several minutes to run, apparently in the classloader???
    }
}

1 Ответ

0 голосов
/ 13 февраля 2019

Оказывается, что при некоторых обстоятельствах, когда вы смешиваете jar из разных версий java (скажем, 1.5 и 1.8), JIT поднимает руки и работает в интерпретированном режиме. На веб-сайте Oracle есть несколько сообщений о поведении, которые говорят: «Мы не знаем, почему это происходит, мы не будем это исправлять».

Я скачал исходники для библиотек, которые не были скомпилированы в 1.8 и собраны из исходного кода, и все хорошо.

...