Skip to content

Instantly share code, notes, and snippets.

@rednaxelafx
Created February 25, 2011 10:31
Show Gist options
  • Save rednaxelafx/843622 to your computer and use it in GitHub Desktop.
Save rednaxelafx/843622 to your computer and use it in GitHub Desktop.
find out the correspondence between the tid/nid of Java threads as shown from jstack/JMX, on HotSpot/Linux

In HotSpot, a Java thread may have a couple of different IDs, depending on the context.

Java-level thread ID

This ID could be fetched from java.lang.Thread.getId() or java.lang.management.ThreadMXBean.getAllThreadIds(). It's platform independent.

In Oracle/Sun's JDK implementation, this ID is simply a auto-incrementing long, starting from 1, assigned to each Java-level java.lang.Thread object when they're initialized.

Quote from java.lang.management.ThreadMXBean's JavaDoc:

Thread ID

Thread ID is a positive long value returned by calling the Thread.getId() method for a thread. The thread ID is unique during its lifetime. When a thread is terminated, this thread ID may be reused.

Some methods in this interface take a thread ID or an array of thread IDs as the input parameter and return per-thread information.

Native thread ID

This ID is highly platform dependent. It's the nid in jstack thread dumps.

  • On Windows, it's simply the OS-level thread ID within a process.

  • On Linux, it's the pid of the thread (which in turn is a light-weight process).

  • On Solaris, it's the thread as returned by thr_self().

  • On Mac OS X, it is said to be the native pthread_t value.

The Address of a C++-level Thread/JavaThread object

This is also platform dependent. It's the tid in jstack thread dumps.

The valid stack memory region of a JavaThread

In JavaThread::print_on(outputStream*) const:

  // print guess for valid stack memory region (assume 4K pages); helps lock debugging
  st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12));

That's the last pair of brackets in a jstack output for Java threads. If it's showing "0x0000000000000000", then last_Java_sp == NULL, which means there is no last Java frame for this thread.

The correspondence? Serviceability Agent to the rescue

See the Java source files in this gist. To compile them, Project Lombok's lombok.jar and JDK's sa-jdi.jar are required on classpath.

package fx.jvm.hotspot.tools;
import java.util.List;
import sun.jvm.hotspot.tools.Tool;
public class PrintThreadIds extends Tool {
public static void main(String[] args) {
PrintThreadIds tool = new PrintThreadIds();
tool.start(args);
tool.stop();
}
@Override
public void run() {
List<ThreadInfo> infos = ThreadUtils.getAllThreadInfos();
for (ThreadInfo info : infos) {
System.out.printf("Thread@%s: tid=%d nid=0x%x\n",
info.getAddress(), info.getTid(), info.getNid());
}
}
}
[sajia@v036122 experiment]$ groovysh
Groovy Shell (1.7.7, JVM: 1.6.0_25-ea)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------------------------------------------------------------
groovy:000> import java.lang.management.ManagementFactory
===> [import java.lang.management.ManagementFactory]
groovy:000> threadMXBean = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@1966c114
groovy:000> threadMXBean.allThreadIds
===> [J@69408a75
groovy:000> println threadMXBean.allThreadIds
[19, 12, 10, 4, 3, 2, 1]
===> null
[sajia@v036122 satest]$ jstack 32133
2011-02-25 17:16:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b08 mixed mode):
"Attach Listener" daemon prio=10 tid=0x0000000060460000 nid=0x7dc8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-4" daemon prio=10 tid=0x00002aaab4041000 nid=0x7d9f in Object.wait() [0x000000004167c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf0120> (a java.util.LinkedList)
at java.lang.Object.wait(Object.java:485)
at java.util.prefs.AbstractPreferences$EventDispatchThread.run(AbstractPreferences.java:1461)
- locked <0x00000000eebf0120> (a java.util.LinkedList)
"Timer-0" daemon prio=10 tid=0x00002aaab4063800 nid=0x7d9e in Object.wait() [0x0000000040df7000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
"Low Memory Detector" daemon prio=10 tid=0x000000005f804000 nid=0x7d9c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=10 tid=0x000000005f802000 nid=0x7d9b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=10 tid=0x000000005f7fc800 nid=0x7d9a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x000000005f7fa000 nid=0x7d99 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=10 tid=0x000000005f7d6000 nid=0x7d98 in Object.wait() [0x0000000042286000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x000000005f7d4000 nid=0x7d97 in Object.wait() [0x0000000042185000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
"main" prio=10 tid=0x000000005f772000 nid=0x7d91 runnable [0x0000000040204000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:220)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
- locked <0x00000000eedb8f60> (a java.io.BufferedInputStream)
at jline.Terminal.readCharacter(Terminal.java:99)
at jline.UnixTerminal.readVirtualKey(UnixTerminal.java:128)
at jline.ConsoleReader.readVirtualKey(ConsoleReader.java:1453)
at jline.ConsoleReader.readBinding(ConsoleReader.java:654)
at jline.ConsoleReader.readLine(ConsoleReader.java:494)
at jline.ConsoleReader.readLine(ConsoleReader.java:448)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.readLine(InteractiveShellRunner.groovy:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.run(ShellRunner.groovy:57)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$run(InteractiveShellRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:127)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:147)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.run(InteractiveShellRunner.groovy:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:442)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:381)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.Main.main(Main.groovy:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
"VM Thread" prio=10 tid=0x000000005f7cf800 nid=0x7d96 runnable
"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000005f785000 nid=0x7d92 runnable
"GC task thread#1 (ParallelGC)" prio=10 tid=0x000000005f787000 nid=0x7d93 runnable
"GC task thread#2 (ParallelGC)" prio=10 tid=0x000000005f788800 nid=0x7d94 runnable
"GC task thread#3 (ParallelGC)" prio=10 tid=0x000000005f78a800 nid=0x7d95 runnable
"VM Periodic Task Thread" prio=10 tid=0x000000005f80f000 nid=0x7d9d waiting on condition
JNI global references: 1539
[sajia@v036122 satest]$ java -classpath .:$JAVA_HOME/lib/sa-jdi.jar fx.jvm.hotspot.tools.PrintThreadIds 32133
Attaching to process ID 32133, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b08
Thread@0x0000000060460000: tid=19 nid=0x7dc8
Thread@0x00002aaab4041000: tid=12 nid=0x7d9f
Thread@0x00002aaab4063800: tid=10 nid=0x7d9e
Thread@0x000000005f804000: tid=7 nid=0x7d9c
Thread@0x000000005f802000: tid=6 nid=0x7d9b
Thread@0x000000005f7fc800: tid=5 nid=0x7d9a
Thread@0x000000005f7fa000: tid=4 nid=0x7d99
Thread@0x000000005f7d6000: tid=3 nid=0x7d98
Thread@0x000000005f7d4000: tid=2 nid=0x7d97
Thread@0x000000005f772000: tid=1 nid=0x7d91
[sajia@v036122 experiment]$ groovysh
Groovy Shell (1.7.7, JVM: 1.6.0_25-ea)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------------------------------------------------------------
groovy:000> import java.lang.management.ManagementFactory
===> [import java.lang.management.ManagementFactory]
groovy:000> threadMXBean = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@1966c114
groovy:000> threadMXBean.allThreadIds
===> [J@69408a75
groovy:000> println threadMXBean.allThreadIds
[19, 12, 10, 4, 3, 2, 1]
===> null
[sajia@v036122 satest]$ jstack 32133
2011-02-25 17:16:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b08 mixed mode):
"Attach Listener" daemon prio=10 tid=0x0000000060460000 nid=0x7dc8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-4" daemon prio=10 tid=0x00002aaab4041000 nid=0x7d9f in Object.wait() [0x000000004167c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf0120> (a java.util.LinkedList)
at java.lang.Object.wait(Object.java:485)
at java.util.prefs.AbstractPreferences$EventDispatchThread.run(AbstractPreferences.java:1461)
- locked <0x00000000eebf0120> (a java.util.LinkedList)
"Timer-0" daemon prio=10 tid=0x00002aaab4063800 nid=0x7d9e in Object.wait() [0x0000000040df7000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x00000000eebf01b0> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
"Low Memory Detector" daemon prio=10 tid=0x000000005f804000 nid=0x7d9c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=10 tid=0x000000005f802000 nid=0x7d9b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=10 tid=0x000000005f7fc800 nid=0x7d9a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x000000005f7fa000 nid=0x7d99 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=10 tid=0x000000005f7d6000 nid=0x7d98 in Object.wait() [0x0000000042286000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x00000000eebfa8a8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x000000005f7d4000 nid=0x7d97 in Object.wait() [0x0000000042185000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x00000000eebfa840> (a java.lang.ref.Reference$Lock)
"main" prio=10 tid=0x000000005f772000 nid=0x7d91 runnable [0x0000000040204000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:220)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
- locked <0x00000000eedb8f60> (a java.io.BufferedInputStream)
at jline.Terminal.readCharacter(Terminal.java:99)
at jline.UnixTerminal.readVirtualKey(UnixTerminal.java:128)
at jline.ConsoleReader.readVirtualKey(ConsoleReader.java:1453)
at jline.ConsoleReader.readBinding(ConsoleReader.java:654)
at jline.ConsoleReader.readLine(ConsoleReader.java:494)
at jline.ConsoleReader.readLine(ConsoleReader.java:448)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.readLine(InteractiveShellRunner.groovy:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.work(ShellRunner.groovy:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at org.codehaus.groovy.tools.shell.ShellRunner.run(ShellRunner.groovy:57)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.super$2$run(InteractiveShellRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:127)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuper0(ScriptBytecodeAdapter.java:147)
at org.codehaus.groovy.tools.shell.InteractiveShellRunner.run(InteractiveShellRunner.groovy:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:266)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:442)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:149)
at org.codehaus.groovy.tools.shell.Groovysh.run(Groovysh.groovy:381)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:63)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
at org.codehaus.groovy.tools.shell.Main.main(Main.groovy:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
"VM Thread" prio=10 tid=0x000000005f7cf800 nid=0x7d96 runnable
"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000005f785000 nid=0x7d92 runnable
"GC task thread#1 (ParallelGC)" prio=10 tid=0x000000005f787000 nid=0x7d93 runnable
"GC task thread#2 (ParallelGC)" prio=10 tid=0x000000005f788800 nid=0x7d94 runnable
"GC task thread#3 (ParallelGC)" prio=10 tid=0x000000005f78a800 nid=0x7d95 runnable
"VM Periodic Task Thread" prio=10 tid=0x000000005f80f000 nid=0x7d9d waiting on condition
JNI global references: 1539
[sajia@v036122 satest]$ java -classpath .:$JAVA_HOME/lib/sa-jdi.jar fx.jvm.hotspot.tools.PrintThreadIds 32133
Attaching to process ID 32133, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b08
Thread@0x0000000060460000: tid=19 nid=0x7dc8
Thread@0x00002aaab4041000: tid=12 nid=0x7d9f
Thread@0x00002aaab4063800: tid=10 nid=0x7d9e
Thread@0x000000005f804000: tid=7 nid=0x7d9c
Thread@0x000000005f802000: tid=6 nid=0x7d9b
Thread@0x000000005f7fc800: tid=5 nid=0x7d9a
Thread@0x000000005f7fa000: tid=4 nid=0x7d99
Thread@0x000000005f7d6000: tid=3 nid=0x7d98
Thread@0x000000005f7d4000: tid=2 nid=0x7d97
Thread@0x000000005f772000: tid=1 nid=0x7d91
package fx.jvm.hotspot.tools;
import lombok.Data;
import sun.jvm.hotspot.debugger.Address;
@Data(staticConstructor="of")
public class ThreadInfo {
private final Address address;
private final long tid;
private final long nid;
}
package fx.jvm.hotspot.tools;
import java.util.ArrayList;
import java.util.List;
import sun.jvm.hotspot.debugger.Address;
import sun.jvm.hotspot.oops.Field;
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.oops.LongField;
import sun.jvm.hotspot.oops.Oop;
import sun.jvm.hotspot.runtime.JavaThread;
import sun.jvm.hotspot.runtime.Threads;
import sun.jvm.hotspot.runtime.VM;
public class ThreadUtils {
public static List<ThreadInfo> getAllThreadInfos() {
List<ThreadInfo> infos = new ArrayList<ThreadInfo>();
Threads threads = VM.getVM().getThreads();
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
Address address = thread.getAddress();
long tid = getTid(thread);
long nid = Long.parseLong(thread.getThreadProxy().toString());
infos.add(ThreadInfo.of(address, tid, nid));
}
return infos;
}
public static long getTid(JavaThread thread) {
final long BAD_TID = -1L;
Oop threadObj = thread.getThreadObj();
Klass klass = threadObj.getKlass();
if (!(klass instanceof InstanceKlass)) return BAD_TID;
InstanceKlass instanceKlass = (InstanceKlass) klass;
Field tidField = instanceKlass.findField("tid", TypeCode.LONG);
if (!(tidField instanceof LongField)) return BAD_TID;
long tid = ((LongField) tidField).getValue(threadObj);
return tid;
}
}
package fx.jvm.hotspot.tools;
public interface TypeCode {
String BOOLEAN = "Z";
String BYTE = "B";
String CHAR = "C";
String SHORT = "S";
String INT = "I";
String LONG = "J";
String FLOAT = "F";
String DOUBLE = "D";
}
@tinybyte
Copy link

Hi, one thing I am not very clear is what you said about nid:

On Linux and Solaris, it's the pid of the thread (which in turn is a light-weight process).

In Solaris, one process may have many light weight processes(http://java.sun.com/docs/hotspot/threads/threads.html), which lwp ids are you referring? From what you said, it sounds like a pid is the same as lwp id, but they are not the same right?

@rednaxelafx
Copy link
Author

Hi tinybyte,

The nid on Solaris is the thread ID returned by thr_self(). Does that answer your question?

HotSpot VM keeps these two fields in its Solaris version of OSThread implementation:

  thread_t _thread_id;      // Solaris thread id
  unsigned int  _lwp_id;    // lwp ID, only used with bound threads

nid in jstack is the _thread_id value. I'm sorry if I made any confusion in this gist. Thank you for the question :-)

@rednaxelafx
Copy link
Author

A related changeset in OpenJDK:

http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/0368109684cb

7132070: Use a mach_port_t as the OSThread thread_id rather than pthread_t on BSD/OSX

Summary: Change OSThread to use mach thread_t

@andymalakov
Copy link

Great stuff. Just verified on Windows7 (Where 'nid' matches native HANDLE of corresponding OS thread).

Thanks,
Andy

@tcheng
Copy link

tcheng commented Aug 1, 2013

Thanks for sharing. It's really helpful.

Tina

@magicliang
Copy link

I still don't get what tid is in the context of "The Address of a C++-level Thread/JavaThread object". Can you give more detail about why it is designed and how it can be used for monitoring/analyzing? Thank you.

@buzzerrookie
Copy link

I still don't get what tid is in the context of "The Address of a C++-level Thread/JavaThread object". Can you give more detail about why it is designed and how it can be used for monitoring/analyzing? Thank you.

In Hotspot, a Thread object is represented by a JavaThread, which is written in C++.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment