Вопросы производительности Java приложений Андрей Дмитриев Инженер-программист Sun Microsystems Февраль 2008.

Презентация:



Advertisements
Похожие презентации
Лекция 1 Раздел 1 Windows Phone Темы раздела 3 Windows Phone Устройство на платформе Windows Phone 4.
Advertisements

Лекция 2 Раздел 2.1 Windows Phone Темы раздела 3.
Таблица умножения на 8. Разработан: Бычкуновой О.В. г.Красноярск год.
Проектирование архитектуры ИСО 1. UML 2 Структура определения языка 4.

САОД кафедра ОСУ 1 Основные абстрактные типы данных Схема процесса создания программ для решения прикладных задач ВУ.
Учебный курс Объектно-ориентированный анализ и программирование Лекция 7 Методы как средство реализации операций Лекции читает кандидат технических наук.
Фрагмент карты градостроительного зонирования территории города Новосибирска Масштаб 1 : 6000 Приложение 7 к решению Совета депутатов города Новосибирска.
1. Определить последовательность проезда перекрестка
Программная инженерия Дмитриев Андрей Владиславович
1 Знаток математики Тренажер Таблица умножения 2 класс Школа 21 века ®м®м.
Фрагмент карты градостроительного зонирования территории города Новосибирска Масштаб 1 : 4500 к решению Совета депутатов города Новосибирска от
Применение генетических алгоритмов для генерации числовых последовательностей, описывающих движение, на примере шага вперед человекоподобного робота Ю.К.
Матемтааки ЕТ СТ 2 класс Шипилова Наталия Викторовна учитель начальных классов, ВКК Шипилова Наталия Викторовна учитель начальных классов, ВКК.
Фрагмент карты градостроительного зонирования территории города Новосибирска Масштаб 1 : 6000 Приложение 7 к решению Совета депутатов города Новосибирска.
Изучение динамического определения типов. Класс Class. Динамическая загрузка и инстанцирование классов. В Java вся информация о классе хранится в специальном.
Программная инженерия Дмитриев Андрей Владиславович
Работа учащегося 7Б класса Толгского Андрея. Каждое натуральное число, больше единицы, делится, по крайней мере, на два числа: на 1 и на само себя. Если.
1 До зеленых человечков: исследовательское тестирование приложений для мобильных Роман Твердохлебов, Санкт-Петербург.
Типы данных Инна Исаева. Переменные Переменная - это как ящик, в котором можно хранить данные. Каждая переменная имеет своё имя, она служит для хранения.
Транксрипт:

Вопросы производительности Java приложений Андрей Дмитриев Инженер-программист Sun Microsystems Февраль 2008

2 Что такое производительность? Вычислительная сложность. Использование памяти. Скорость запуска приложения. Запас прочности и расширяемость. Видимая скорость.

3 Вычислительная сложность Количество операций в единицу времени. Накладные расходы на вызов методов. Сложность алгоритма для данного класса задач.

4 Использование памяти Количество памяти, требуемое для обычной работы программы, должно быть минимизировано. Увеличение нагрузки на систему не должно выражаться в существенном росте потребления памяти. Не должно быть «потерянной памяти» (memory leak).

5 Скорость запуска Время, необходимое для запуска приложения может быть критично. Виртуальная машина может оптимизировать некоторые методы для скорейшего их исполнения. Программа может не обладать всей функциональностью в начале запуска.

6 Расширяемость Простота поддержки системы. «Предсказуемость» поведения приложения при повышении нагрузок.

7 Видимая скорость Приложение может обладать некими характеристиками, благоприятно влияющими на общее впечатление от программы. Действительная производительность может не соответствовать идеальной картине.

8 Программа Введение. – Цикл проекта по оптимизации. – Инструментарий. Вопросы программирования. – Ввод-вывод. – Использование памяти. – Сложность алгоритма. Использование системных возможностей. –Настройки сборщик а мусора. –Другие в озможности виртуальной машины.

9 Процесс по оптимизации Анализ. Дизайн. Реализация. Тестирование.

10 Анализ Является первым шагом при > При проектировании > При оптимизации Требует наличия некоторых требований, от которых можно оттолкнуться. > Минимум памяти. > Минимальная скорость CPU. > Минимальная скорость соединения. > И др. Profiling – поиск областей, где тратится наибольшее количество ресурсов. > При профилировании происходит сбор информации о показателях программы в тех или иных ситуациях. > Профилирование часто связано с анализом полученных данных.

11 Дизайн Создание общей схемы системы с различной степенью детализации. Могут быть использованы различные методологии. При оптимизации это оценка, теоретическое доказательство предполагаемого подхода.

12 Реализация Стиль написания или изменения программы имеет ключевое влияние на качество программы. При оптимизации накладываются качественные рамки в виде тестов на производительность на код.

13 Тестирование На этапе оптимизации предполагается, что качество достигло необходимого уровня. Построение базы тестов должно начинаться на самых ранних этапах создания или оптимизации системы. Benchmarking – сравнение показателей двух различных случаев. Тестирование производительности важнее, чем тестирование качества.

14 Как оценивать производительность? Запуск приложения. Открытие большого документа. Длительность выполнения запроса. И т.п.

15 Измерение временных интервалов Инструментирование кода. Программные вызовы (System.currentTimeMillis()). Системные возможности. Эталонные тесты. Micro benchmark – многократное выполнение конкретного действия. Macro benchmark - многократное выполнение конкретного действия в совокупности с типичным набором сопутствующих операций. Сюиты могут выравнивать дисперсию результатов, увеличивая число попыток.

16 Узкие места программы (hot spot, bottleneck) Это методы или блоки кода, которые выполняются дольше всего, вызываются наиболее часто, требуют больше всего памяти. Стратегии. Реализовать эффективнее, сделать быстрее часто исполняемые методы. Минимизировать число вызовов медленных методов.

17 Состояние среды исполнения Возможности VM позволяют: составлять слепки области памяти в любой момент времени; считывать данные о загрузке процессора.

18 Структура области памяти Итоги размещения данных в памяти: > java -Xrunhprof Application Dumping Java heap... allocation sites... done. percent live alloc'ed stack class rank self accum bytes objs bytes objs trace name % 13.83% char[] % 19.68% java.lang.String % 21.87% byte[] % 23.47% byte[] % 24.64% byte[] % 25.67% int[] % 26.46% byte[] % 27.20% int[] % 27.84% …

19 Структура области памяти Стек вызовов методов в приложении: TRACE : java.lang.String. (String.java:208) java.lang.StringBuilder.toString(StringBuilder.java:430) javax.swing.plaf.basic.BasicTextUI.getActionMap(BasicTextUI.java :493) javax.swing.plaf.basic.BasicTextUI.installKeyboardActions(BasicT extUI.java:378)

20 Загрузка процессора java -Xprof Application Interpreted + native Method 18.5% sun.awt.Win32GraphicsEnvironment.initDisplay 3.7% sun.nio.cs.ISO_8859_1$Decoder.decodeArrayLoop 1.9% sun.awt.windows.WDataTransferer.registerClipboard 1.9% sun.awt.windows.WComponentPeer.pShow 1.9% java.lang.ClassLoader$NativeLibrary.load 1.9% java.lang.ClassLoader$NativeLibrary.find 1.9% sun.awt.windows.WToolkit.getScreenInsets 1.9% java.lang.Throwable.fillInStackTrace 1.9% sun.awt.windows.WFramePeer.setState 1.9% java.io.WinNTFileSystem.canonicalizeWithPrefix0 …

21 Дополнительный инструментарий jmap – утилита для сохранения данных о структуре данных в куче. jhat – анализатор отчетов утилиты jmap. JConsole – удаленное профилирование приложений.

22 Выводы Под «производительностью» можно подразумевать различные физические параметры. Приложение может снабжаться своим тестовым набором. JDK поставляется с базовым профилирующим инструментарием. Среда разработки или специализированные приложения могут предоставлять богатые возможности для отладки и профилирования.

23 Ввод/вывод Пакет java.io предоставляет широкий спектр классов для работы с потоками данных. Различные классы показывают лучшую производительность для разных задач.

24 Буферизация данных Скорость чтения и записи на диск уменьшается при уменьшении блока данных. Создание промежуточного буфера может принести существенное улучшение производительности. Буферизация может осуществляться и средствами самой программы.

25 Взаимодействие с файловой системой Виртуальная машина сама инициирует множество обращений к файловой системе. Изменение поведения программы может повлиять на поведение виртуальной машины. Существуют утилиты (filemon), отслеживающие все обращения указанного процесса к файловой системе.

26 Использование памяти Использованная память (RAM footprint) программы включает в себя классы, объекты. Класс java.lang.Runtime предоставляет функциональность для определения свободной и занятой памяти в куче. Для оценки объема памяти, занятой приложением в целом, можно использовать средства платформы.

27 В памяти VM (heap) можно выделить данные нескольких типов: Классы Объекты Потоки Системные структуры данных Системный код и библиотеки Из чего состоит занятая память?

28 Размер объекта Определяется суммой размеров всех полей класса (включая super). Виртуальная машина может выравнивать блоки. class DataStorage{ int index; //4 байта byte value; //1 байт float rgbModel; //4 байта double cmyModel; //8 байт long nativeData; //8 байт //super -ссылка (обычно 4 байта) }

29 Размер класса Класс содержит: байткод, структуру методов и полей класса (необходима VM), данные из пула констант, предкомпилированный код (Just-In-Time, JIT).

30 Загрузка классов Виртуальная машина загружает классы по мере необходимости. Подсчет количества классов позволяет оценить суммарный объем. Особенно важен при работе по сети.

31 Список загруженных классов Команда java –verbose Application составляет список всех классов, загруженных в память в данном сеансе работы. [Loaded sun.swing.CachedPainter from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded javax.Painter from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded sun.swing.CachedPainter$Cache from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded sun.swing.CachedPainter$Entry from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded java.awt.GradientPaint from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded java.awt.RenderingHints from C:\jdk1.6.0\jre\lib\rt.jar] [Loaded sun.awt.SunHints from C:\jdk1.6.0\jre\lib\rt.jar] …

32 Контроль загрузки классов Загрузка большого количества классов может существенно увеличить объем используемой памяти. Загрузка класса также требует от VM выполнения поисковой операции. Класс загружается при: > Создании экземпляра класса, > Обращении к статическому полю или методу, > Использовании в instanceof. Работа с объектами из С/С++ кода подчиняется тем же правилам.

33 Утечка памяти Обзор Garbage Collector. Причины возникновения утечек. Способы отслеживания. Методы предотвращения утечек.

34 Сборщик мусора Технология автоматической сборки объектов, на которые отсутствуют жесткие ссылки позволяет не заботиться об освобождении памяти. У программиста нет надежных способов воздействовать на сборщик мусора.

35 Как теряется память? Несмотря на надежность работы GC, количество используемой программой памяти может увеличиваться. Программа может не хранить прямые ссылки на объект, но содержать объект в составе коллекции. При использовании JNI, ресурсы платформы не отслеживаются сборщиком мусора.

36 Отслеживание утечек Поиск класса, количество экземпляров которого растет. Системный ресурс: отслеживание с помощью диспетчера задач. Java ресурс: отслеживание с помощью профилировщика. Выделение областей в программе, где данные экземпляры создаются. Допустимо контролировать размер всех коллекций.

37 Предотвращение утечек Реализация. Применение метода коллекции remove() для ненужных более объектов. Организация проекта. Создание сюиты нагрузочных тестов для приложения. Модульное тестирование.

38 Насколько сильно потоки замедлят мое приложение? Поток занимает место как объект и требует дополнительной памяти для хранения стека и, возможно, системных ресурсов. Способ реализации потоков заложен в виртуальную машину. Использование потоков может существенно улучшить скорость работы приложения.

39 Оптимизация загрузки классов Задача. Приложение должно обрабатывать различные типы документов. Каждому документу назначается класс Translator. Приложение может реализовать паттерн фабрика, возвращая конкретную реализацию класса Translator.

40 Неудачное решение public static Translator getTranslator(String fileType) { if (fileType.equals("doc")) { return new WordTranslator(); } else if (fileType.equals("html")) { return new HTMLTranslator(); } else if (fileType.equals("txt")) { return new PlainTranslator(); } else if (fileType.equals("xml")) { return new XMLTranslator(); } else { return new DefaultTranslator(); } При компиляции метода (JIT) загружаются все используемые классы.

41 Экономичное решение Отложим действия по разрешению нужного класса до этапа выполнения. Для этого используем механизм reflection. try { if (fileType.equals("doc")) { return (Translator)Class.forName( "WordTranslator").newInstance(); } else if (fileType.equals("html")) { return (Translator)Class.forName("HTMLTranslator").newInstance(); } else if (fileType.equals("txt")) { return (Translator)Class.forName("PlainTranslator").newInstance(); } else if (fileType.equals("xml")) { return (Translator)Class.forName("XMLTranslator").newInstance(); } else { return new DefaultTranslator();} } catch (Exception e) { return new DefaultTranslator(); }

42 Оценка количества классов Программа обрабатывает сообщения от трех кнопок: public class Listener1 extends JFrame { public Listener1() { JButton open = new JButton("Open"); JButton close = new JButton("Close"); JButton save = new JButton("Save"); getContentPane().setLayout(new FlowLayout()); getContentPane().add(open); getContentPane().add(close); getContentPane().add(save); open.addActionListener(new OpenAction()); //для каждого компонента нужен класс close.addActionListener(new CloseAction()); //если компонентов много, то save.addActionListener(new SaveAction()); //загружается чересчур много классов setVisible(true); }

43 Оценка количества классов (cont.) Каждый слушатель – это внутренний класс. protected void open() { //Open a file } protected void close() { //Close a file } protected void save() { //Save a file } class OpenAction implements ActionListener { public void actionPerformed(ActionEvent e) { open(); } } class CloseAction implements ActionListener { public void actionPerformed(ActionEvent e) { close(); } } class SaveAction implements ActionListener { public void actionPerformed(ActionEvent e) { save(); } } public static void main(String[] args) { new Listener1(); } }

44 Совмещение слушателей Внедрение логики в один из классов-слушателей позволяет переложить на него выбор действия. class ButtonAction implements ActionListener { public void actionPerformed(ActionEvent e) { String action = (JButton)e.getSource().getText(); if ( action.equals("Open") ) { open(); } else if (action.equals("Close")) { close(); } else if (action.equals("Save")) { save(); Какие сложности привносит данный код в программу?

45 Использование общего слушателя Теперь достаточно одного класса для всех компонентов интерфейса. ActionListener listener = new ButtonAction(); open.addActionListener(listener); close.addActionListener(listener); save.addActionListener(listener);

46 Недостатки данного решения Плохая структурированность программы: блок switch. Зависимость от имен компонентов. Сложность поддержки.

47 Использование отражения Также может уменьшить количество классов. class ReflectiveAction implements ActionListener { String methodName; Object target; public ReflectiveAction(Object target, String methodName) { this.target = target; this.methodName = methodName; } …

48 Использование отражения (cont.) Данный метод осуществляет вызов установленного на этапе создания объекта обработчика для сообщений. … public void actionPerformed(ActionEvent e) { try { Class[] argTypes = {}; Method method = target.getClass().getMethod(methodName, argTypes); Object[] args = {}; method.invoke(target, args); } catch (Exception ex) { ex.printStackTrace(); }}}

49 Использование отражения (cont.) Потребуется создавать несколько экземпляров для различных компонентов. open.addActionListener(new ReflectiveAction(this, "open")); close.addActionListener(new ReflectiveAction(this, "close")); save.addActionListener(new ReflectiveAction(this, "save")); Можно объединять одинаковые компоненты одним таким классом. Код не сильно усложняется.

50 Дальнейшее улучшение Применить паттерн Заместитель (proxy) для того, чтобы переиспользовать объекты в течение жизни программы. Этим можно достичь константного количества экземпляров классов во время исполнения программы.

51 Пример: запуск приложений в одной JVM Каждое Java приложение требует для своей работы JVM. Второе приложение, запущенное стандартным способом, не имеет возможности выполняться внутри уже существующей JVM. Приложения, работающие в разных JVM, не имея возможности их разделять, дублируют все классы.

52 Структура сложного приложения Существует офисный пакет из нескольких приложений. Электронная таблица: public class Spreadsheet { public static void main(String[] args) { JFrame f = new JFrame("Spreadsheet"); JTable table = new JTable(20,5); JScrollPane scroller = new JScrollPane(table); f.setContentPane(scroller); f.setBounds(10,10,200,200); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); } }

53 Структура сложного приложения (cont.) Текстовый процессор. public class WordProcessor { public static void main(String[] args) { JFrame f = new JFrame("WordProcessor"); JTextArea text = new JTextArea("Type Here"); JScrollPane scroller = new JScrollPane(text); f.setContentPane(scroller); f.setBounds(10,10,200,200); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); } }

54 Показатели запуска приложений > java Spreadsheet > java Wordprocessor

55 Реализация запуска в одной JVM При попытке запустить приложение: Загрузчик определяет, есть ли уже готовая JVM? Если есть, то запустить приложение в ней и выйти. Если нет, то запустить новую JVM и остаться в памяти слушать последующие обращения.

56 Класс Launcher В первый раз запускает JVM с сервисом. Для взаимодействия использует класс Socket. public class Launcher { static final int socketPort = 9876; public static void main(String[] args) { Launcher l = new Launcher(); l.launch(args[0]); } …

57 Класс Launcher (cont.) Попытка найти другие JVM с включенным сервисом: public void launch(String className) { boolean launched = false; while (!launched) { Socket s = findService(); if (s != null) { System.out.println("found service"); …

58 Класс Launcher (cont.) Передача сервису имени класса приложения, который нужно запустить: OutputStream oStream = s.getOutputStream(); byte[] bytes = className.getBytes(); oStream.write(bytes.length); oStream.write(bytes); oStream.close(); launched = true; System.out.println(className);

59 Класс Launcher (cont.) Если сервиса еще нет, то создаем его: System.out.println("Starting new service"); ServerSocket server = new ServerSocket(socketPort); Launcher.go(className); Thread listener = new ListenerThread(server); listener.start(); launched = true; System.out.println("started service listener");

60 Сервисный класс Класс постоянно находится в ожидании подключения по сети. public class ListenerThread extends Thread { ServerSocket server; public ListenerThread(ServerSocket socket) { this.server = socket; } public void run() { while (true) { … String className = new String(bytes); Launcher.go(className); }

61 Запуск работающей JVM Приложение запускается посредством обращения к его методу main() через механизм отражения. class Launcher… public static void go(final String className) { Thread thread = new Thread() { public void run() { Class clazz = Class.forName(className); Method method = clazz.getMethod("main", {String[].class}); method.invoke(clazz, {new String[0]}); } thread.start(); }

62 Результат работы загрузчика Приложения разделяют ресурсы между собой.

63 Изменяемость объекта Объект может обладать свойством сохранять свое состояние без изменения. По статистике, такие объекты существуют недолго. Наоборот, изменяемый объект предназначен для длительной работы. VM осуществляет мощных оптимизации над неизменяемыми объектами. > Строка – неизменяемый объект. > Все методы по модификации строки создают новые объекты.

64 Неизменяемое значение или ссылка? Модификатор final предотвращает изменение: public class Fruits { public static final String[] names = {apple", banana"}; } Fruits.names = new String[50]; //запрещено Fruits.names[1] = grape; //разрешено

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

66 Алгоритмы и структуры данных Выбор алгоритма обработки данных может существенно повлиять на производительность. Принцип организации данных в коллекциях объектов важен для выбора подходящей реализации.

67 Два алгоритма подсчета суммы прогрессии public class SimpleSummer { public long sum(int start, int stop){ long acc = 0; for(int i=start;i

68 Рекурсия Вызов функцией самой себя естественным образом накладывается на некоторые прикладные задачи. Эффективность рекурсии должна быть оценена с позиции: использования памяти (метод может использовать промежуточные данные), глубины (стек вызовов требует больше памяти).

69 Выбор структуры данных Набор коллекций (пакет java.util) Java состоит из: > Списков (List), > Множеств (Set), > Ассоциативных массивов (Map). Каждый тип содержит несколько различных реализаций. > Применимость того или иного конкретного класса оценивается по роду задачи. > Поиск > Модификация > Выборка.

70 Синхронизация коллекций Позволяет исключить параллельный доступ к данным коллекции: import java.util.Collections; List list = Collections.synchronizedList(new ArrayList()); Этим привносятся дополнительные накладные расходы на работу с данными.

71 Неизменяемые коллекции Предотвращает изменение данных коллекции. import java.util.Collections; List list = Collections.unmodifiableList(new ArrayList()); Исключаются действия по копированию данных, необходимые поддержания содержимого в необходимом порядке.

72 Выводы Производительность алгоритма зависит от области его применения. Коллекции Java предоставляют широкий набор структур, алгоритмов и возможностей для работы с данными.

73 Системнозависимый код Использование JNI в Java приложениях может быть оправдано: Нужно наладить взаимодействие с существующим С кодом. При реализации JVM. Стоит задача внедрения JVM в другую программу. Вызов функций, специфичных для операционной системы. Доступ к специальным аппаратным устройствам. Создание критичных по времени выполнения частей кода.

74 Системнозависимый код (cont.) Вызов Java-Java может быть быстрее Java-C (и С-Java) вызовов в несколько раз. Скорость обработки JNI вызовов находится в зависимости от реализации JVM.

75 Сборка мусора Почему нужно иметь в виду данный фактор? Гарантии, даваемые GC. Жизненный цикл объекта. Ссылки на объекты.

76 Ссылки по теме Effective Java, J. Bloch Java Platform performance, S.Wilson, J.Kesselman Java Performance Tuning, Jack Shirazi Ken Arnold, James Gosling, The Java programming language. Richard Jones, Garbage collection: algorithms for automatic dynamic memory management. Liang Sheng, The Java Native Interface. Platform Computing. Multithreaded and Networked Programming, Thomas W. Christopher and George K. Thiruvathukal.

Q&A

Вопросы производительности Java приложений Андрей Дмитриев Инженер-программист Sun Microsystems Февраль 2008