Выявление неисправностей приложений
Материал из BiTel WiKi
Удаленная отладка
Необходимо запустить приложение со следующими ключами:
-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=5589,server=y,suspend=n
После этого можно создать в Eclipse конфигурацию запуска Remote Java Application, поставить точку останова и отлаживать удаленный процесс как локальный. Естесственно, что нужно организовать доступ к порту на машине с процессом (5589) с машины с запущенной IDE.
Метод подходит для выявления воспроизводимых ошибок непосредственно на работающем приложении.
Снятие стека
Выполняется утилитой jstack, входящей в комплект JDK. Она снимает стэк конкртного java-процесса. Например у нас есть такие процессы в системе:
bg-bill1:/usr/local/BGBillingServer # ps axwww | grep java 2701 ? Sl 33:15 /opt/java/jre/bin/java -Dapp.name=BGBillingServer -Dnetworkaddress.cache.ttl=3600 -Xmx1000m -cp .:./lib/* ru.bitel.common.bootstrap.Boot bitel.billing.server.Server start 2703 ? Sl 1:11 /usr/java/default/bin/java -Dapp.name=BGIPNNetflowCollector -Dlog4j.configuration=log4j-collector.xml -Dlog.dir.path=log/ -Dnetworkaddress.cache.ttl=3600 -Xmx256m -Djava.awt.headless=true -cp .:./lib/* bitel.billing.server.netflow.ipn.Collector start 2721 ? Sl 17:15 /usr/java/default/bin/java -Dapp.name=BGRadiusDialup -Xmx256m -Dlog4j.configuration=log4j-radius.xml -Dlog.dir.path=log/ -cp .:./lib/* bitel.billing.server.radius.Radius start 2753 ? Sl 21:15 /opt/java/jre/bin/java -Dapp.name=BGScheduler -Xmx1000m -cp .:./lib/* ru.bitel.common.bootstrap.Boot bitel.billing.server.TaskExecuter -estart 3656 ? Sl 0:04 /opt/java/jre/bin/java -Dapp.name=BGDataLoader -Dnetworkaddress.cache.ttl=3600 -Xmx1000m -cp .:./lib/* ru.bitel.common.bootstrap.Boot bitel.billing.server.DataLoader -estart 8822 pts/1 R+ 0:00 grep java
Мы решили снять стэк с процесса сервера BGBilling (код 2701) :
bg-bill1:/usr/local/BGBillingServer # /opt/java/jdk/bin/jstack 2701 | more 2009-06-23 14:46:04 Full thread dump Java HotSpot(TM) Server VM (11.2-b01 mixed mode): "Attach Listener" daemon prio=10 tid=0x08310000 nid=0x2285 waiting on condition [0x00000000..0x00000000] java.lang.Thread.State: RUNNABLE "http-8080-8" daemon prio=10 tid=0x08c89c00 nid=0x1fb2 in Object.wait() [0x6fd7e000..0x6fd7f150] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x7720d2e8> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at java.lang.Object.wait(Object.java:485) at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:416) - locked <0x7720d2e8> (a org.apache.tomcat.util.net.JIoEndpoint$Worker) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:442) at java.lang.Thread.run(Unknown Source) "http-8080-7" daemon prio=10 tid=0x08536000 nid=0x1eaf in Object.wait() [0x7005c000..0x7005d150] java.lang.Thread.State: WAITING (on object monitor) .....
Метод хорошо подходит для определения причины "зависания" плиложений по причине взаимоблокировок процессов (Dead Lock). Подобные блокировки определяются автоматически с указанием строк исходного кода.
Снятие дампа памяти
jmap -dump:format=b,file=snapshot.jmap PID_OF_PROCESS
Просмотр дампа:
jhat -J-mx512m snapshot.jmap
Утилиты jmap, jhat входят в Sun JDK. Следует учитывать, что для просмотра дампа размером Х приложению jhat потребуется выделить объем памяти примерно X*3 - X*4. В приведенном примере выделено 512 МБ. Полученный результат можно можно смотреть через web-интерфейс. Для этого надо зайти на http://localhost:7000 . Для того, чтобы подменить порт нужно указывать -port x в команде jhat
Также в составе JDK поставляется утилита jvisualvm - GUI приложение для просмотра файлов с дампом памяти.