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

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

Я отследил его до конструктора класса 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, и, хотя я могу печатать текст на консоли во время открытия Notepad (если я поместил код до первой инициализации JFrame) ), вышеуказанная проблема означает, что перед тем, как окно станет видимым, будет задержка почти на целую секунду. Нужно ли будет использовать другой язык или графический интерфейс для достижения желаемой производительности?


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

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

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

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

Ответы [ 5 ]

9 голосов
/ 10 августа 2011

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

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

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

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

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

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

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


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

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

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

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


Один обходной путь - отключить 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 против 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, но я заметил значительную загрузку нативных классов ", установка UI "(загрузка свойств пользовательского интерфейса по умолчанию и т. д.) и тому подобное. К сожалению, я не думаю, что с этим можно что-то сделать (говорите, если есть).


Заключительные мысли

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

2 голосов
/ 08 августа 2011

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

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

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

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

1 голос
/ 08 августа 2011

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

1 голос
/ 08 августа 2011

Mac OS X 10.5.8, Java 1.6.0_26. Не удивительно, учитывая время запуска JVM и создание мощного графического однорангового узла.

247 for first JFrame.
0 for second JFrame.

Приложение: Согласно статье Производительность Java: время запуска , Java Quick Starter может быть доступен на вашей платформе.

1 голос
/ 08 августа 2011

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

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