OpenJdk начальное время запуска очень медленно - PullRequest
4 голосов
/ 26 апреля 2019

Я использую openjdk 11.0.3 на сервере. Всякий раз, когда сервер перезагружался (каждую ночь): для первого первоначального запуска моего Приложения пользователи должны ждать 35 секунд, прежде чем приложение будет даже запущено. (До того, как первый System.out.println будет написан из основного метода.) (Хотя последующие запуски происходят очень быстро) Я пробовал следующий вариант для отладки этого:

-Xlog:class+load:file=classload.txt

Вот наиболее важные находки:

... 
[2.284s][info][class,load] jdk.internal.loader.URLClassPath$FileLoader source: jrt:/java.base
[5.032s][info][class,load] sun.security.rsa.RSASignature$SHA1withRSA source: jrt:/java.base
…
[5.051s][info][class,load] java.util.LinkedList$Node source: jrt:/java.base 
[8.121s][info][class,load] pos.LFChangeable source: file:/C:/Users/rho/AppData/Roaming/edapp/pos.jar
…
[8.135s][info][class,load] java.io.FileNotFoundException source: jrt:/java.base
[10.584s][info][class,load] sun.reflect.misc.ReflectUtil source: jrt:/java.base
…
[11.744s][info][class,load] java.security.NoSuchAlgorithmException source: jrt:/java.base
[34.853s][info][class,load] jdk.internal.logger.DefaultLoggerFinder source: jrt:/java.base

Почему он зависает в течение 23 секунд между загрузкой java.security.NoSuchAlgorithmException и jdk.internal.logger.DefaultLoggerFinder? А как насчет других секунд замедлений?

редактирование: Основываясь на комментариях, я уточню некоторые. Это сервер Windows RDP. На самом деле это более одного сервера, но проблема сохраняется на всех серверах. Приложение является отдельным приложением. Поэтому каждое утро возникают проблемы, так как пользователи, которые входят в систему, чтобы запустить Приложение, будут пытаться запустить его несколько раз, когда «ничего не происходит». Сейчас я несколько раз пытался перезапустить один из серверов, и вот что я нашел:

Запуск моего приложения с java11 после перезагрузки занимает в среднем 40 секунд до первого System.out.println. Тогда до моего первого шоу JFrame осталось всего 1-2 секунды. Запуск моего приложения с java8 (sun) после перезагрузки занимает в среднем 16 секунд до первого System.out.println. Но затем я получаю 25-секундную задержку, прежде чем мой первый JFrame показывает. Запуск моего приложения с java11 после того, как он уже запущен с java8, занимает в среднем 4-6 секунд.

Ответы [ 2 ]

2 голосов
/ 29 апреля 2019

Возможно, ваше приложение страдает от отсутствия «архива обмена данными класса (CDS)». Такой архив позволяет намного быстрее загружать стандартные классы и был создан по умолчанию некоторыми установщиками предыдущих версий, но OpenJDK 11 не имеет установщика.

Это решено JEP 341 :

В настоящее время образ JDK включает в себя список классов по умолчанию, сгенерированный во время сборки, в каталоге lib. Пользователи, которые хотят воспользоваться преимуществами CDS, даже имея только список классов по умолчанию, предоставленный в JDK, должны запустить java -Xshare:dump в качестве дополнительного шага. Эта опция задокументирована, но многие пользователи не знают об этом.

Так что, хотя этот JEP о том, что JDK 12 выполняет необходимые шаги автоматически, он также упоминает исправление для JDK 11: просто запустите java -Xshare:dump в командной строке один раз, чтобы сгенерировать архив.

Обратите внимание, что вы можете еще больше увеличить время запуска, включив классы приложений в CDS. См. Также раздел Совместное использование данных класса документации JDK 11.

0 голосов
/ 14 мая 2019

Я сейчас тщательно протестировал и готов опубликовать свои результаты вместе с двумя различными «решениями», которые я сделал. Во-первых, позвольте мне немного объяснить мою заявку. Это корпоративное приложение, которое появилось 13 лет назад и с тех пор расширяется. Следовательно, это приложение большого размера, выполняет много разных задач (хотя большинство пользователей использует только его часть) и имеет около 120 jar-файлов в своем classpath, включая все сторонние jar-файлы. Как упоминалось ранее, после перезапуска сервера требуется 35 секунд, прежде чем будет показан мой первый логин-JFrame.

Решение 1: Это было мое первое решение, и это не решение для медленного запуска, а скорее решение для пользователя, не запускающего несколько экземпляров приложения. Я заметил, что хотя мое приложение было очень медленным при первом начальном запуске, другие приложения не были. Поэтому обходным путем было создание небольшого автономного приложения для отображения заставки, которое я запускаю в своей программе следующим образом:

splashProcess = Runtime.getRuntime().exec("javaw -jar splash.jar");

Позже я просто убью его с помощью

splashProcess.destroy();

Обратите внимание, что если мне нужно создать заставку с новым JFrame (), то для его отображения потребуется 35 секунд.

Решение 2: Во время тестирования я обнаружил, что могу смоделировать перезапуск, просто удалив все jar-файлы и скопировав их обратно. В дополнение к сокращению времени тестирования я обнаружил, что запуск приложения только с 4-5 jar-файлами, необходимыми для первоначального запуска, был очень быстрым (хотя это привело бы к исключениям ClassNotFoundException позже), это также означает, что я мог попытаться выяснить, какой jar-файл привел к зависанию, начав с копирования всех jar-файлов обратно, а затем пропустив один и еще один. Однако я узнал, что виноват был не один файл jar. Количество секунд, необходимое для запуска приложения, постепенно уменьшалось при каждом удалении некоторых jar-файлов. Таким образом, кажется, что проблема заключается в том, что при первом вызове new JFrame () в моем приложении java, похоже, создает какой-то индекс или что-то вроде всех классов в classpath, хотя они не используются в настоящее время. Я не знаю, почему это происходит, но этот процесс занимает довольно много времени с 120 jar-файлами на пути к классам. Это привело меня к решению № 2. Когда мое приложение теперь запускается, я проверяю аргумент «startSilent». Если это присутствует, единственное, что делает мое приложение, это показывает новый JDialog с размером 0,0, а затем вызывает System.exit (0); Затем я создал скрипт, который запускает мое приложение с параметром «startSilent», который запускается при входе пользователя в систему. Теперь, если пользователь входит на сервер и ждет, по крайней мере, 35 секунд, прежде чем запускать наше приложение, запуск теперь происходит молниеносно, так как приложение уже запустилось и закрылось один раз, так что «classpath-index» или что-то еще был построен. Если пользователь запускает приложение через более короткое время, время запуска уменьшается за счет того, как долго беззвучный сценарий уже запущен. (И запуск всегда будет, по крайней мере, на несколько порядков быстрее, чем раньше, поскольку сценарий запускается до того, как рабочий стол будет готов).

Итак, это результаты моих открытий. Я надеюсь, что другие найдут их полезными, и если кто-то может объяснить, почему то, что я называю «индекс-пути к классам», создано как есть, я был бы рад.

...