Шта је Тхреад Думп и како их анализирати?

Хајде да разговарамо о думпу нити и како га анализирати.

Такође ћемо разговарати о томе како помаже да се прецизирају проблеми и неки од анализатора које можете да користите.

Шта је Тхреад?

Процес је рачунарски програм који се учитава у меморију рачунара и који се извршава. Може се извршити помоћу процесора или скупа процесора. Процес је описан у меморији са важним информацијама као што су складишта променљивих, ручке датотека, програмски бројач, регистри, и, сигнали, итд.

Процес се може састојати од много лаких процеса који се називају нити. Ово помаже да се постигне паралелизам у коме је процес подељен на више нити. Ово резултира бољим перформансама. Све нити унутар процеса деле исти меморијски простор и зависе једна од друге.

Тхреад Думпс

Када се процес извршава, можемо детектовати тренутно стање извршења нити у процесу помоћу думпова нити. Думп нити садржи снимак свих нити активних у одређеном тренутку током извршавања програма. Садржи све релевантне информације о нити и њеном тренутном стању.

Модерна апликација данас укључује више бројева нити. Свака нит захтева одређене ресурсе, обавља одређене активности везане за процес. Ово може повећати перформансе апликације јер нити могу да користе доступна ЦПУ језгра.

Али постоје компромиси, нпр. понекад више нити можда неће добро да координирају једна с другом и може доћи до застоја. Дакле, ако нешто крене наопако, можемо да користимо думпове нити да проверимо стање наших нити.

Думп нити у Јави

Думп ЈВМ нити је листа стања свих нити које су део процеса у том одређеном тренутку. Садржи информације о стеку нити, представљене као траг стека. Како је написано у отвореном тексту, садржај се може сачувати за накнадни преглед. Анализа депонија нити може помоћи

  • Оптимизација ЈВМ перформанси
  • Оптимизација перформанси апликације
  • Дијагностиковање проблема, нпр. застоја, сукоба нити итд.

Генерисање Тхреад Думпова

Постоји много начина за генерисање думпова нити. Испод су неки алати засновани на ЈВМ-у и могу се извршити из командне линије/терминала (ЦЛИ алати) или директоријума /бин (ГУИ алати) директоријума за инсталацију Јаве.

Хајде да их истражимо.

#1. јСтацк

Најједноставнији начин да генеришете думп нити је коришћење јСтацк-а. јСтацк се испоручује са ЈВМ-ом и може се користити из командне линије. Овде нам је потребан ПИД процеса за који желимо да генеришемо думп нити. Да бисмо добили ПИД, можемо користити јпс команду као што је приказано испод.

јпс -л

јпс наводи све ИД-ове Јава процеса.

На Виндовс-у

C:Program FilesJavajdk1.8.0_171bin>jps -l
47172 portal
6120 sun.tools.jps.Jps
C:Program FilesJavajdk1.8.0_171bin>

На Линук-у

[[email protected] ~]# jps -l
1088 /opt/keycloak/jboss-modules.jar
26680 /var/lib/jenkins/workspace/kyc/kyc/target/kyc-1.0.jar
7193 jdk.jcmd/sun.tools.jps.Jps
2058 /usr/share/jenkins/jenkins.war
11933 /var/lib/jenkins/workspace/admin-portal/target/portal-1.0.jar
[[email protected] ~]#

Као што видимо овде, добијамо листу свих покренутих јава процеса. Садржи локални ВМ ИД за покренути јава процес и назив апликације у колонама један и два. Сада, да генеришемо думп нити, користимо програм јСтацк са заставицом –л који креира дугу листу излаза дампа. Такође можемо послати излаз у неку текстуалну датотеку по нашем избору.

јстацк -л 26680

[[email protected] ~]# jstack -l 26680
2020-06-27 06:04:53
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):

"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"logback-8" #2316 daemon prio=5 os_prio=0 tid=0x00007f07e0033000 nid=0x4792 waiting on condition [0x00007f07baff8000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"logback-7" #2315 daemon prio=5 os_prio=0 tid=0x00007f07e0251800 nid=0x4791 waiting on condition [0x00007f07bb0f9000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

#2. јвисуалвм

Јвисуалвм је ГУИ алат који нам помаже да решимо проблеме, надгледамо и профилишемо Јава апликације. Такође долази са ЈВМ-ом и може се покренути из /бин директоријума наше јава инсталације. Веома је интуитиван и једноставан за коришћење. Између осталих опција, такође нам омогућава да ухватимо думп нити за одређени процес.

  Управљајте састанцима помоћу софтвера за заказивање на мрежи [11 Calendly Alternatives]

Да бисмо видели думп нити за одређени процес, можемо кликнути десним тастером миша на програм и изабрати Тхреад Думп из контекстног менија.

#3. јцмд

ЈЦМД је услужни програм командне линије који се испоручује са ЈДК-ом и користи се за слање дијагностичких командних захтева ЈВМ-у.

Међутим, ради само на локалној машини на којој је покренута Јава апликација. Може се користити за контролу Јава снимања летова, дијагностицирање и решавање проблема са ЈВМ и Јава апликацијама. Можемо да користимо команду Тхреад.принт из јцмд-а да добијемо листу думпова нити за одређени процес који је наведен у ПИД-у.

Испод је пример како можемо да користимо јцмд.

јцмд 28036 Тхреад.принт

C:Program FilesJavajdk1.8.0_171bin>jcmd 28036 Thread.print
28036:
2020-06-27 21:20:02
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):

"Bundle File Closer" #14 daemon prio=5 os_prio=0 tid=0x0000000021d1c000 nid=0x1d4c in Object.wait() [0x00000000244ef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Unknown Source)
        at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.getNextEvent(EventManager.java:403)
        - locked <0x000000076f380a88> (a org.eclipse.osgi.framework.eventmgr.EventManager$EventThread)
        at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:339)

"Active Thread: Equinox Container: 0b6cc851-96cd-46de-a92b-253c7f7671b9" #12 prio=5 os_prio=0 tid=0x0000000022e61800 nid=0xbff4 waiting on condition [0x00000000243ee000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x000000076f388188> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000021a7b000 nid=0x2184 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x00000000219f5000 nid=0x1300 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000219e0000 nid=0x48f4 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000219df000 nid=0xb314 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000219db800 nid=0x2260 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000219d9000 nid=0x125c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000219d8000 nid=0x834 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001faf3000 nid=0x36c0 in Object.wait() [0x0000000021eae000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000005806000 nid=0x13c0 in Object.wait() [0x00000000219af000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076f398178> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Unknown Source)
        at java.lang.ref.Reference.tryHandlePending(Unknown Source)
        - locked <0x000000076f398178> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)

"main" #1 prio=5 os_prio=0 tid=0x000000000570e800 nid=0xbf8 runnable [0x0000000000fec000]
   java.lang.Thread.State: RUNNABLE
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at java.util.zip.ZipFile.<init>(Unknown Source)
        at org.eclipse.osgi.framework.util.SecureAction.getZipFile(SecureAction.java:307)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getZipFile(ZipBundleFile.java:136)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.lockOpen(ZipBundleFile.java:83)
        at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getEntry(ZipBundleFile.java:290)
        at org.eclipse.equinox.weaving.hooks.WeavingBundleFile.getEntry(WeavingBundleFile.java:65)
        at org.eclipse.osgi.storage.bundlefile.BundleFileWrapper.getEntry(BundleFileWrapper.java:55)
        at org.eclipse.osgi.storage.BundleInfo$Generation.getRawHeaders(BundleInfo.java:130)
        - locked <0x000000076f85e348> (a java.lang.Object)
        at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:599)
        at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:1)
        at org.eclipse.equinox.weaving.hooks.SupplementerRegistry.addSupplementer(SupplementerRegistry.java:172)
        at org.eclipse.equinox.weaving.hooks.WeavingHook.initialize(WeavingHook.java:138)
        at org.eclipse.equinox.weaving.hooks.WeavingHook.start(WeavingHook.java:208)
        at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startActivator(FrameworkExtensionInstaller.java:261)
        at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startExtensionActivators(FrameworkExtensionInstaller.java:198)
        at org.eclipse.osgi.internal.framework.SystemBundleActivator.start(SystemBundleActivator.java:112)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:815)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:808)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:765)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule.initWorker(EquinoxBundle.java:190)
        at org.eclipse.osgi.container.SystemModule.init(SystemModule.java:99)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:272)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:257)
        at org.eclipse.osgi.launch.Equinox.init(Equinox.java:171)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:316)
        at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:661)
        at org.eclipse.equinox.launcher.Main.basicRun(Main.java:597)
        at org.eclipse.equinox.launcher.Main.run(Main.java:1476)

"VM Thread" os_prio=2 tid=0x000000001fae8800 nid=0x32cc runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000005727800 nid=0x3264 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000005729000 nid=0xbdf4 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000572a800 nid=0xae6c runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000572d000 nid=0x588 runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000572f000 nid=0xac0 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000005730800 nid=0x380 runnable

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000005733800 nid=0x216c runnable

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000005734800 nid=0xb930 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x0000000021a8d000 nid=0x2dcc waiting on condition

JNI global references: 14


C:Program FilesJavajdk1.8.0_171bin>

#4. ЈМЦ

ЈМЦ је скраћеница од Јава Миссион Цонтрол. То је ГУИ алат отвореног кода који се испоручује са ЈДК и користи се за прикупљање и анализу података јава апликације.

Може се покренути из /бин фолдера наше Јава инсталације. Јава администратори и програмери користе алат за прикупљање детаљних информација ниског нивоа о понашању ЈВМ-а и апликација. Омогућава детаљну и ефикасну анализу података које прикупља Јава Флигхт Рецордер.

Када покренемо јмц, можемо видети листу јава процеса који се покреће на локалној машини. Могућа је и даљинска веза. У одређеном процесу можемо да кликнемо десним тастером миша и изаберемо Старт Флигхт Рецординг, а затим проверимо исписе нити на картици Тхреадс.

#5. јцонсоле

јцонсоле је алатка Јава Манагемент Ектенсион која се користи за управљање жалбама и праћење.

Такође има скуп унапред дефинисаних операција на ЈМКС агенту које корисник може да изврши. Омогућава кориснику да открије и анализира праћење стека програма уживо. Може се покренути из /бин фолдера наше Јава инсталације.

  Шта је средњи софтвер?

Користећи јцонсоле ГУИ алат, можемо да прегледамо праћење стека сваке нити када га повежемо са покренутим јава процесом. Затим, на картици Тхреад, можемо видети називе свих покренутих нити. Да бисмо открили застој, можемо кликнути на Детецт Деадлоцк у доњем десном углу прозора. Ако се детектује застој, појавиће се на новој картици, у супротном ће бити приказано Без застоја.

#6. ТхреадМкБеан

ТхреадМКСБеан је интерфејс за управљање системом нити Јава виртуелне машине која припада пакету јава.ланг.Манагемент. Углавном се користи за откривање нити које су ушле у ситуацију застоја и добијање детаља о њима.

Можемо користити ТхреадМкБеан интерфејс да програмски ухватимо думп нити. гетТхреадМКСБеан() метода МанагементФацтори се користи за добијање инстанце ТхреадМКСБеан интерфејса. Враћа број живих нити демонских и не-демон. МанагементФацтори је фабричка класа за добијање управљаних бинова за Јава платформу.

private static String getThreadDump (boolean lockMonitors, boolean lockSynchronizers) {
    StringBuffer threadDump = new StringBuffer (System.lineSeparator ());
    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean ();
    for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads (lockMonitors, lockSynchronizers)) {
        threadDump.append (threadInfo.toString ());
    }
    return threadDump.toString ();
}

Ручна анализа депонија нити

Анализа думпова нити може бити веома корисна у прецизирању проблема у вишенитним процесима. Проблеми као што су застоји, сукоби око закључавања и прекомерно коришћење ЦПУ-а од стране појединачних думпова нити могу се решити визуелизацијом стања појединачних думпова нити.

Максимална пропусност апликације се може постићи исправљањем статуса сваке нити након анализе думпа нити.

На пример, рецимо, процес користи много ЦПУ-а, можемо сазнати да ли било која нит највише користи ЦПУ. Ако постоји таква нит, конвертујемо њен ЛВП број у хексадецимални број. Затим из думпа нити можемо пронаћи нит са нид једнаким претходно добијеном хексадецималном броју. Користећи траг стека нити можемо прецизно одредити проблем. Хајде да сазнамо ИД процеса нити користећи доњу команду.

пс -мо пид,лвп,стиме,тиме,цпу -Ц јава

[[email protected] ~]# ps -mo pid,lwp,stime,time,cpu -C java
       PID        LWP         STIME           TIME              %CPU
26680               -         Dec07          00:02:02           99.5
         -       10039        Dec07          00:00:00           0.1
         -       10040        Dec07          00:00:00           95.5

Хајде да погледамо испод депонију нити. Да бисте добили думп нити за процес 26680, користите јстацк -л 26680

[[email protected] ~]# jstack -l 26680
2020-06-27 09:01:29
<strong>Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):</strong>

"Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

.
.
.
.
.
.
.
"<strong>Reference Handler</strong>" #2 daemon prio=10 os_prio=0 tid=0x00007f085814a000 nid=0x6840 in Object.wait() [0x00007f083b2f1000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x00000006c790fbd0> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=0 tid=0x00007f0858140800 nid=0x683f runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f0858021000 nid=0x683b runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f0858022800 nid=0x683c runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0858024800 nid=0x683d runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0858026000 nid=0x683e runnable

"VM Periodic Task Thread" os_prio=0 tid=0x00007f08581a0000 nid=0x6847 waiting on condition

JNI global references: 1553

Сада, хајде да видимо које су ствари које можемо да истражимо користећи дампове нити. Ако посматрамо думп нити, можемо видети много садржаја, што може бити неодољиво. Међутим, ако идемо корак по корак, то може бити прилично једноставно за разумевање. Хајде да разумемо први ред

2020-06-27 09:01:29
Думп пуне нити Јава ХотСпот(ТМ) 64-битни сервер ВМ (мешовити режим 25.221-б11):

Горе приказано време када је думп генерисан и информације о ЈВМ-у који је коришћен. Следеће, на крају, можемо видети листу нити, прва међу њима је наша РеференцеХандлер нит.

Анализа блокираних нити

Ако анализирамо доње евиденције думп-а нити, можемо открити да је детектовао нити са статусом БЛОЦКЕД, што чини перформансе апликације веома спорим. Дакле, ако можемо да пронађемо БЛОКИРАНЕ нити, можемо покушати да издвојимо нити повезане са бравама које нити покушавају да добију. Анализа трага стека из нити која тренутно држи браву може помоћи у решавању проблема.

[[email protected] ~]# jstack -l 26680
.
.
.
.
" DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
"DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
.
.
.
.

Анализирање мртве тачке

Још једна веома често коришћена примена думпова нити је откривање застоја. Откривање и решавање застоја може бити много лакше ако анализирамо дампове нити.

Мртво закључавање је ситуација која укључује најмање две нити у којој је ресурс потребан једној нити за наставак извршавања закључан од стране друге нити и истовремено, ресурс потребан другој нити је закључан од стране прве нити.

  Зашто је Дарк Соулс тако тежак?

Дакле, ниједна нит не може да настави са извршавањем, а то доводи до застоја и завршава се заглављивањем апликације. Ако су присутни дредови, онда ће последњи део думпа нити одштампати информације о застоју на следећи начин.

"Thread-0":
waiting to lock monitor 0x00000250e4982480 (object 0x00000000894465b0, a java.lang.Object),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x00000250e4982380 (object 0x00000000894465a0, a java.lang.Object),
which is held by "Thread-0"
.
.
.
"Thread-0":
at DeadlockedProgram$DeadlockedRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465b0> (a java.lang.Object)
- locked <0x00000000894465a0> (a java.lang.Object)
at java.lang.Thread.run([email protected]/Thread.java:844)
"Thread-1":
at DeadlockedProgram $DeadlockRunnableImplementation.run(DeadlockedProgram.java:34)
- waiting to lock <0x00000000894465a0> (a java.lang.Object)
- locked <0x00000000894465b0> (a java.lang.Object)
at java.lang.Thread.run([email protected]/Thread.java:844)

Овде можемо видети информације о застоју у прилично разумљивом формату.

Осим овога, ако сумирамо сав горњи део думп-а нити, онда то наводи доле наведене информације.

  • Референтни руковалац је човеку читљиво име нити.
  • #2 је јединствени ИД нити.
  • демон означава да ли је нит демонска нит.
  • Нумерички приоритет нити је дат са прио=10.
  • Тренутни статус нити се означава са чекањем под условом.
  • Затим видимо праћење стека, које укључује информације о закључавању.

Анализатори дампова нити

Поред ручне анализе, доступни су бројни алати за анализу депонија нити, како онлајн тако и офлајн. Испод су неки од наведених алата, које можемо користити на основу захтева.

Прво, хајде да истражимо онлајн алате.

#1. Брзи конац

Фаст Тхреад је омиљени алат за анализу депонија нити за решавање сложених производних проблема ДевОпс инжењера. Ово је онлајн анализатор дампова Јава нити, можемо да отпремимо думп нити као датотеку или можемо директно да копирамо и налепимо думп нити.

У зависности од величине, анализираће думп нити и приказати информације као што је приказано на снимку екрана.

Карактеристике

  • Решавање проблема са рушењем ЈВМ-а, успоравањем, цурењем меморије, замрзавањем, скоковима ЦПУ-а
  • Инстант РЦА (не чекајте продавце)
  • Интуитивна контролна табла
  • РЕСТ АПИ подршка
  • Машинско учење

#2. Спотифи Тхреад Думп Анализер

Тхе Спотифи Тхреад Думп Анализер је лиценциран под верзијом 2.0 Апацхе лиценце. То је онлајн алатка и прихвата думп нити као датотеку или можемо директно да копирамо и налепимо думп нити. У зависности од величине, анализираће думп нити и приказати информације као што је приказано на снимку екрана.

#3. Јстацк преглед

Јстацк.ревиев анализира исписе јава нити из претраживача. Ова страница је само на страни клијента.

#4. Сајт 24×7

Ово оруђе је предуслов за откривање неисправних нити које деградирају перформансе Јава виртуелне машине (ЈВМ). Проблеми као што су застоји, сукоби око закључавања и прекомерно коришћење ЦПУ-а од стране појединачних думпова нити могу се решити визуелизацијом стања појединачних думпова нити.

Максимална пропусност апликације се може постићи исправљањем статуса сваке нити коју пружа алатка.

Сада, хајде да истражимо офлајн алате.

Када је у питању профилисање, само најбољи алат је довољно добар.

#1. ЈПрофилер

ЈПрофилер је један од најпопуларнијих анализатора депоније нити међу Јава програмерима. ЈПрофилер-ов интуитивни кориснички интерфејс вам помаже да решите уска грла у перформансама, откријете цурење меморије и разумете проблеме са нитима.

ЈПрофилер подржава профилисање на следећим платформама:

  • Виндовс
  • мацОС
  • Линук
  • ФрееБСД
  • Соларис
  • АИКС
  • ХП-УКС

Испод су неке функције које ЈПрофилер чине најбољим избором за профилисање наших апликација на ЈВМ-у.

Карактеристике

  • Подржава профилисање базе података за ЈДБЦ, ЈПА и НоСКЛ
  • Доступна је и подршка за издање Јава Ентерприсе
  • Представља информације високог нивоа о РМИ позивима
  • Звездана анализа цурења меморије
  • Обимне КА могућности
  • Интегрисани профилатор нити је чврсто интегрисан са приказима профилисања ЦПУ-а.
  • Подршка за платформе, ИДЕ и сервере апликација.

#2. ИБМ ТМДА

ИБМ Тхреад анд Монитор Думп Анализер за Јава (ТМДА) је алатка која омогућава идентификацију застоја, застоја, сукоба са ресурсима и уских грла у депонијама Јава нити. То је ИБМ производ, али ТМДА алат је обезбеђен као без икакве гаранције или подршке; међутим, они покушавају да поправе и побољшају алат током времена.

#3. МанагеЕнгине

МанагеЕнгине менаџер апликација може помоћи у надгледању ЈВМ Хеап и не-Хеап меморије. Можемо чак и да конфигуришемо прагове и да будемо упозорени путем е-поште, СМС-а итд, и да обезбедимо да је Јава апликација добро подешена.

#4. ИоурКит

ИоурКит састоји се од доле наведених производа који се називају комплетом.

  • Јава Профилер – Потпуно опремљен програмер за ниско оптерећење за Јава ЕЕ и Јава СЕ платформе.
  • ИоуМонитор – Праћење и профилисање перформанси Јенкинс, ТеамЦити, Градле, Мавен, Ант, ЈУнит и ТестНГ.
  • .НЕТ Профилер – Лак за коришћење перформансе и профилер меморије за .НЕТ фрамеворк.

Закључак

Сада знате како су думпови нити корисни у разумевању и дијагностиковању проблема у вишенитним апликацијама. Са одговарајућим знањашто се тиче думпова нити – њихове структуре, информација садржаних у њима и тако даље – можемо их користити да брзо идентификујемо узроке проблема.