Подтвердить что ты не робот

Первый вызов конструктора JFrame занимает много времени во время запуска приложения Swing (из-за java.awt.Window())

Я пытаюсь создать простое, легкое и отзывчивое приложение с использованием Java Swing. Однако, когда он запускается, перед окном (JFrame) появляется заметная задержка ( > 500 мс).

Я отследил его до конструктора класса java.awt.Window, который является предком JFrame.

Как ни странно, конструктор работает только медленно для первого вызова. Если я создаю несколько объектов JFrame, время, затраченное на конструктор, составляет ~ 600 мс для первого объекта, но обычно измеряется как 0мс для последующих объектов.

Вот простой пример, который в моей системе показывает эту значительную задержку для первого вызова конструктора, но не второго:

public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            long start;

            start = System.currentTimeMillis();
            JFrame frame1 = new JFrame();
            System.out.println((System.currentTimeMillis() - start) + " for first JFrame.");

            start = System.currentTimeMillis();
            JFrame frame2 = new JFrame();
            System.out.println((System.currentTimeMillis() - start) + " for second JFrame.");
        }
    });
}

С типичным выходом:

641 for first JFrame.
0 for second JFrame.

Если я добавлю эту инициализацию объекта Window перед объектами JFrame:

java.awt.Window window = new java.awt.Window(null);

Затем вывод изменяется на что-то вроде:

578 for first Window.
47 for first JFrame.
0 for second JFrame.

Когда я пытаюсь сделать то же самое с суперклассом Window, java.awt.Container, конструктор Window по-прежнему остается тем, что занимает много времени (поэтому проблема не выходит за класс Window).

Так как конструктор JFrame вызывает конструктор Window, это, как представляется, указывает на то, что первый вызов конструктора Window является дорогостоящим.

Что происходит при первом вызове конструктора, который занимает так много времени, и есть ли что-нибудь, что я могу с этим сделать? Есть ли какое-то простое исправление или проблема, фундаментальная для Swing/AWT? Или это может быть проблемой, характерной для моей системы/настройки?

Я хотел бы, чтобы мое приложение открывалось так быстро (или почти так же быстро), как MS Notepad, и, хотя я могу напечатать текст на консоли примерно за раз, когда открывается Блокнот (если я поместил код перед первой инициализацией JFrame), вышеуказанная проблема означает, что перед тем, как окно станет видимым, почти целая секунда задержки. Должен ли я использовать другой язык или графический интерфейс для получения производительности, которую я буду после?


Изменить. Если я добавлю Thread.sleep(10000) в качестве первой строки run(), результаты не изменяются (они появляются только через 10 секунд). Это говорит о том, что проблема не вызвана каким-то асинхронным кодом запуска, а вызвана непосредственно вызовом конструктора.

Изменить 2: реализовано, что профилировщик NetBeans может прорисовываться внутри классов JRE и обнаружил, что большую часть времени тратится на инициализацию объекта sun.java2d.d3d.D3DGraphicsDevice (для объекта Window нужны экраны и вставки), который является частью "Direct3D Accelerated Rendering Pipeline для платформ Microsoft Windows, включен по умолчанию", представленный в Java 6u10. Его можно отключить, передав в JVM свойство "-Dsun.java2d.d3d = false", что уменьшает время запуска примерно на 3/4, но я еще не уверен, что мне это понадобится (D3D) или если есть другой способ заставить его загружаться быстрее. Вот вывод, если я поставлю этот параметр в командной строке:

0 for first Window
47 for first JFrame.
0 for second JFrame.

Я вернусь и очищу это сообщение после того, как я углубился позже.

4b9b3361

Ответ 1

Этот ответ записывает то, что я нашел до сих пор. Если у кого-то есть дополнительная информация, прокомментируйте или отправьте ответ. Я не полностью удовлетворен просто отключением использования Swing D3D, и я открыт для других решений.

Причина: инициализация D3D

Swing использует Java2D API для рисования, и в соответствии с этим Руководство по поиску и устранению неисправностей Java SE 7, Java2D использует набор конвейеров рендеринга ", могут быть грубо определены как разные способы рендеринга примитивов". Более конкретно, конвейер рендеринга Java2D, по-видимому, связывает межплатформенный Java-код с собственными графическими библиотеками (OpenGL, X11, D3D, DirectDraw, GDI), которые могут поддерживать аппаратное ускорение.

В Java 1.6.0_10 (aka 6u10) в Java2D для Windows был добавлен "полностью аппаратный ускоренный графический конвейер" на основе Direct3D улучшить производительность рендеринга в приложениях Swing и Java2D (по умолчанию включено).

По умолчанию, когда Java2D используется в системе Windows, и этот конвейер Direct3D, и конвейер DirectDraw/GDI по умолчанию включены (я предполагаю, что они используются для разных вещей).

Библиотека D3D, по крайней мере, загружается и инициализируется, когда это необходимо, и встроенная функция инициализации D3D, которая вызывается при первом создании окна (или потомка окна), занимает ~ 500 мс (для меня) и вызывает сообщила о медленности инициализации, и отключение D3D-конвейера, кажется, устраняет вызов этой нативной функции, что значительно сокращает время запуска. (Хотя я бы предпочел задерживать, прекомпетровать, делиться (в разных приложениях Java) или оптимизировать инициализацию D3D, и мне интересно, не слишком ли это для других языков.)

Конечно, возможно, что в большинстве систем время, проведенное в D3D init, незначительно, и это только проблема в моей системе из-за некоторых проблем с оборудованием или драйвером, но я несколько скептически отношусь к этому (хотя, если true, это было бы легко исправить).


Детализация трассировки до исходного initD3D()

Более подробно (пропустите следующий абзац, если вам все равно), я использовал профилировщик и отладчик Netbeans, чтобы найти следующее:

Когда инициализируется JFrame (вызванный конструктор), вызывается конструктор класса предка java.awt.Window. Окно инициализирует свое устройство GraphicsConfiguration, которое пытается извлечь экранное устройство по умолчанию и так далее. В первый раз, когда это происходит (когда первый оконный или оконный потомок инициализируется), экранное устройство не существует, поэтому оно построено. В этом процессе класс sun.java2D.d3d.D3DGraphicsDevice инициализируется и в своем статическом блоке инициализации (см. <clinit> ()) он вызывает встроенную функцию initD3D(), которая занимает значительное время для выполнения (~ 500 мс).

Мне удалось найти версию исходного кода для D3DGraphicsDevice и ее статический блок init (и я действительно просто предполагаю из этого источник, что initD3D() делает его <clinit> () так долго - мой профилировщик, похоже, не признает родные функции, но это разумное предположение).


Один обходной путь - отключить D3D для Java2D

Конвейер D3D можно отключить, запустив java с опцией -Dsun.java2d.d3d=false, согласно этому руководству по свойствам системы Java2D (и также вышеупомянутое руководство по устранению неполадок). Я думаю, что это отключает D3D, но не DirectDraw, который можно отключить с помощью Dsun.java2d.noddraw=true (а затем "все операции будут выполняться с помощью GDI" ), но это не заметно улучшает время инициализации.

Например, для запуска MyJar.jar без D3D я мог бы использовать следующую команду:

java -jar -Dsun.java2d.d3d=false MyJar.jar

С кодом, отправленным в вопросе (который инициализирует Window, а затем 2 объекта JFrame), я получаю такие результаты:

0 for first Window
47 for first JFrame.
0 for second JFrame.

Вместо таких результатов:

547 for first Window
31 for first JFrame.
0 for second JFrame.

(Обратите внимание, что время находится в миллисекундах и измеряется с помощью System.currentTimeMillis() в Windows, которое, как я думаю, имеет разрешение от 15 до 16 мс.)


OpenGL vs Direct3D

OpenGL используется вместо Direct3D, если используется опция -Dsun.java2d.opengl=True. В моей системе есть небольшое улучшение (~ 400 мс для OpenGL против ~ 500 мс для D3D), но задержка по-прежнему заметна.


Другие задержки

Я заметил, что инициализация первого объекта JFrame, даже если он не является первым окном, занимает гораздо больше времени, чем инициализация последующих объектов JFrame (записанных от 31 до 47 мс против 0 мс).

Профилирование указывает, что это связано с созданием первой стеклянной панели (JPanel) и в конечном итоге, по-видимому, вызвано инициализацией/загрузкой Look and Feel и системы внутри класса javax.swing.UIManager и кода инициализации объекта. Это не слишком важно, но это объясняет наблюдаемую аномалию.

В моей реальной программе, которая немного сложнее (необходимо инициализировать больше компонентов Swing), задержки, по-видимому, более диффузно распространяются в коде Swing, но я заметил значительный объем загрузки на родном классе, "установка пользовательского интерфейса" (загрузка свойств пользовательского интерфейса по умолчанию и т.д.) и т.д. К сожалению, я не думаю, что многое можно сделать по этому поводу (пожалуйста, сообщите, если есть).


Закрытие мысли

В конце концов, есть только так много, что можно сделать, и я должен узнать, как далеко зашли Swing и JVM за последние годы.

Ответ 2

Я предполагаю, что он загружает собственные библиотеки. Если это так, вы не можете с этим поделать.

Ответ 4

Создание первой jframe включает загрузку библиотеки swing. JVM не загружает библиотеку, смотрящую на инструкцию import. Библиотеки загружаются только при первом вызове этой библиотеки.

В этом случае создание frame1 является первым оператором, который вызывает библиотеку Swing. Посредством экземпляра time frame2 библиотеки swing уже загружены, и, следовательно, создание объекта для frame2 слишком быстро, даже чтобы заметить некоторое время. Следовательно, оно показывает 0.

Это объясняет, почему он показывает 578, 47, 0, когда вы складываете оператор окна над двумя. Это связано с тем, что первый оператор требует времени для загрузки библиотеки java.awt. Второе занимает время, чтобы загрузить библиотеку swing. И третья показывает 0, поскольку библиотека, необходимая для ее создания, уже загружена.

Вы можете даже проверить его таким образом. Попробуйте заменить второе создание JFrame на JPanel, и он все равно показывает 0.

Ответ 5

Требуется время для загрузки всех классов swing, тогда для загрузки собственных awt-библиотек требуется время. Возможно, загрузка классов занимает больше времени, потому что если вы просто создаете JLabel вместо первого JFrame, это все равно занимает больше времени.