Мониторинг Java-приложений с помощью Health Center API. Часть 2

Добавление в приложение для обнаружения взаимоблокировок представления профилирования методов

Health Center версии 2.1 содержит мощный интерфейс прикладных программ (API). Он позволяет Java-разработчикам внедрять Health Center в свои приложения и использовать его возможности для решения разнообразных проблем. Во второй части этой статьи к приложению для обнаружения взаимоблокировок, разработанному в первой части, добавляется представление профилирования методов для определения того, на что приложение расходует большую часть своих процессорных циклов.

Тоби Корбин, программист, IBM

Тоби Корбин (Toby Corbin) - программист, в настоящее время разрабатывает инструментарий RAS в IBM Java Technology Centre. Он поступил на работу в IBM в 2001 году и четыре года занимался разработкой поддержки национальных языков и глобализации для Java Runtime Environment, а затем два года вел разработку библиотек Swing и AWT.



23.05.2013

IBM® Monitoring and Diagnostics tools for Java - Health Center (Health Center) ― это бесплатный, необременительный для системы диагностический инструмент и API для мониторинга приложений, работающих на IBM Java virtual machine (JVM). Подробности о том, что может делать этот API, см. в Части 1. В этой статье к приложению для обнаружения взаимоблокировок, разработанному в первой части, добавляется представление профилирования методов для определения того, на что приложение расходует большую часть своих процессорных циклов. (Полный исходный код примера для этой статьи содержится в разделе Загрузка.)

Требования к системе

Для установки Health Center API требуется, как минимум, Eclipse 3.4 или Eclipse 4.x.

Тестирование приложения

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

Листинг 1. Фрагмент нового исходного кода GenerateDeadLock
private class runSlowMethods extends Thread {

   public void run() {
      SlowClassAndMethod1 sCAM1 = new SlowClassAndMethod1();
      SlowClassAndMethod2 sCAM2 = new SlowClassAndMethod2();

      sCAM1.start();
      sCAM2.start();
   }

   private class SlowClassAndMethod1 extends Thread {

      public void run() {
         while (true) {
            slowMethod1();
            try {
               Thread.sleep(2000);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }

      private void slowMethod1() {
         String largeString = new String("a string to add");
         for (int i = 0; i < 1000000; i++) {
            largeString.concat(largeString);
         }

      }
   }

   private class SlowClassAndMethod2 extends Thread {

      public void run() {
         while (true) {
            slowMethod2();
            try {
               Thread.sleep(2000);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
         }
      }

      private void slowMethod2() {
         HashMap map = new HashMap();
         String largeString = new String("another string to add");
         for (int i = 0; i < 1000000; i++) {
            map.put(i, largeString);
            largeString.concat(largeString);
         }

      }

Запустите эту программу с подключенным к ней агентом Health Center. Чтобы запустить приложение с агентом на основе Java 5 СР10 / Java 6 SR5 или более поздних версий или Java 7, используйте следующую команду (см. рисунок 1):

java -Xhealthcenter GenerateDeadlock
Рисунок 1. Запуск приложения
Запуск приложения

Чтобы запустить приложение с помощью агента на основе Java 5 SR9 / Java 6 SR4 или более ранних версий, выполните следующую команду:

java -agentlib:healthcenter -Xtrace:output=healthcenter.out GenerateDeadlock

Можно также загрузить комплекты IBM для разработчиков.

Написание расширенного инструмента мониторинга приложений

Чтобы изменить приложение DeadlockDemo, созданное в первой части, откройте файл Application.java (см. рисунок 2).

Рисунок 2. Открытие файла Application.java
Открытие файла Application.java

Замените весь код Application.java новым исходным кодом (см. раздел Загрузка). Пример приведен в листинге 2.

Листинг 2. Фрагмент заменяющего кода Application.java
private class ProfileApplication extends Thread {

   String methodTree = null;

   public void run() {

      try {
         Thread.sleep(10000);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }

      while (keepRunning) {
         analyzeMethods();
         try {
            Thread.sleep(2000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }

   private void analyzeMethods() {
      ProfilingData profilingData;
      profilingData = hcMon.getProfilingData();

      if (profilingData == null) {
         return;
      }

      MethodProfileData[] mPD = profilingData.getProfilingEvents();
      if (mPD != null) {

         final SimpleProfileData[] sPD = new SimpleProfileData[mPD.length];
         int index = 0;
         for (MethodProfileData mP : mPD) {
            methodTree = new String();
            sPD[index] = new SimpleProfileData();
            sPD[index].setCount(mP.getMethodSampleCount());
            sPD[index].setMethodName(mP.getMethodName());
            MethodProfilingNode[] mPN = mP.getCallingMethods();
            for (MethodProfilingNode node : mPN) {
               if (node instanceof MethodProfilingNode) {
                  walkProfileTree(node);
               }
            }
            sPD[index].setMethodTree(methodTree);
            index++;
         }

         Arrays.sort(sPD);

         display.asyncExec(new Runnable() {
            public void run() {

               profileText.setText("method: "
                     + sPD[0].getMethodName()
                     + "\n		sample count:  "
                     + sPD[0].getCount() + "\n"
                     + sPD[0].getMethodName()
                     + sPD[0].getMethodTree());
               shell.redraw();
            }
         });

      }
   }

Этот код отличается от оригинального, но большинство изменений связано с настройкой окон и правильного поведения приложения. Собственно в код Health Center API добавилось лишь несколько вызовов для получения данных профиля метода, которые мы рассмотрим ниже.


Профилирование данных

Health Center использует профилировщик на основе выборки, который отображает все методы, вызываемые приложением. Этот профилировщик полезен для выявления узких мест с точки зрения производительности: приложение может проводить слишком много времени в одном методе.

Для доступа к данным профилирования используется такой же вызов, как и для доступа к данным о потоках:

ProfilingData profilingData = HealthCenter.getProfilingData();

В классе ProfilingData есть методы, которые предоставляют доступ ко всем обнаруженным методам, показывают счетчики интенсивности работы этих методов и отображают иерархию вызовов.

Метод getProfilingEvents() возвращает массив MethodProfileData, содержащий запись для каждого метода из выборки. Для каждого метода можно получить значение счетчика (getMethodSampleCount()), имя метода (getMethodName()) и вызывающие его методы (getCallingMethods()).

Используем эти методы для создания иерархии вызовов наиболее часто извлекаемого метода. Затем воспользуемся этой информацией для точной настройки производительности контролируемого приложения.


Мониторинг взаимоблокировок и профилирование методов

Теперь у нас есть новое приложение для мониторинга взаимоблокировок и профилирования, а также пересмотренная программа, страдающая взаимоблокировками, которая работает в фоновом режиме. Если запустить приложение для мониторинга взаимоблокировок и профилирования, в окне мониторинга приложения появятся сообщения об обнаружении взаимоблокировок (см. рисунок 3).

Рисунок 3. Проверка на взаимоблокировки
Мониторинг взаимоблокировок

Итак, данные у нас есть. Пришло время выяснить, что они означают.


О чем говорят данные профилирования

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

Листинг 3. Результат для верхнего метода
profileText.setText("method: "
   + sPD[0].getMethodName()
   + "\n		sample count:  "
   + sPD[0].getCount() + "\n"
   + sPD[0].getMethodName()
   + sPD[0].getMethodTree());

Его можно изменить, чтобы выводить больше методов, организовав циклический перебор всех элементов массива sPD.

Когда профилировщик работает в Health Center, счетчик метода увеличивается, если он активно выполняет Java-код из стека. Чем выше значение счетчика метода, тем больше работы он выполняет. Счетчик метода может не соответствовать частоте вызовов этого метода. Он свидетельствует о том, как много работы выполняет метод по сравнению с другими методами приложения.

Из данного примера видно, что больше всех работает метод java.util.HashMap.rehash(int). Стек его вызовов (откуда он вызывается) показывает, что вызовы этого метода исходят от GenerateDeadlock$runSlowMethods$SlowClassAndMethod2.run().

Следующий вызов в иерархии показывает, что метод GenerateDeadlock$runSlowMethods$SlowClassAndMethod2.slowMethod2(), который отвечает за вызов метода java.util.HashMap.put, вызывает метод run(). В конечном итоге это приводит к вызову rehash().

Если посмотреть на метод slowMethod2() в приложении со взаимоблокировками, то можно увидеть цикл, который заносит записи в HashMap (см. листинг 4).

Листинг 4. Цикл, который заносит записи в HashMap
private void slowMethod2() {
   HashMap map = new HashMap();
   String largeString = new String("another string to add");
   for (int i = 0; i < 1000000; i++) {
      map.put(i, largeString);
      largeString.concat(largeString);
   }
}

Этот цикл в данном методе можно закомментировать, как показано в листинге 5.

Листинг 5. Цикл закомментирован
   private void slowMethod2() {
      HashMap map = new HashMap();
      String largeString = new String("another string to add");
//      for (int i = 0; i < 1000000; i++) {
//         map.put(i, largeString);
//         largeString.concat(largeString);
//      }
   }

Если теперь перезапустить тестовое приложение, а затем новый инструмент мониторинга взаимоблокировок и профилирования, то окажется, что проблема устранена. На панели профилирования появляется новый метод (см. рисунок 4).

Рисунок 4. Проблема решена — появляется новый метод
Новый метод на панели профилировщика

Теперь этот процесс — который выявляет "горячие" методы и помогает устранять узкие места с точки зрения производительности — можно начинать заново.


Заключение

Эта статья демонстрирует, как приступить к работе с Health Center API. Эти методы можно применять для того, чтобы извлекать из Health Center любые данные и использовать их. Например, используя API, можно получать подробную информацию о методах WebSphere® только тогда, когда они начинают интенсивно использоваться, или запускать дамп системы, когда приложение проявляет признаки дефицита памяти.


Загрузка

ОписаниеИмяРазмер
Исходный код для этой статьиj-healthcareapi2-source.zip3 KБ

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=931138
ArticleTitle=Мониторинг Java-приложений с помощью Health Center API. Часть 2
publish-date=05232013