zoukankan      html  css  js  c++  java
  • 虚拟机stack全分析

    通过jps -lv 获取到本地的一个JVM实例进程。再通过jstack pid  > thread.txt ,把stack trace输出到thread.txt文件中。

    2012-08-28 23:16:39

    Java代码  收藏代码
    1. 2012-08-28 23:16:39  
    2. Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing):  
    3.   
    4. "Attach Listener" daemon prio=10 tid=0xb3da5400 nid=0x13ea waiting on condition [0x00000000]  
    5.    java.lang.Thread.State: RUNNABLE  
    6.   
    7. "Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000]  
    8.    java.lang.Thread.State: TIMED_WAITING (on object monitor)  
    9.     at java.lang.Object.wait(Native Method)  
    10.     at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)  
    11.     - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)  
    12.     at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)  
    13.     at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)  
    14.   
    15. "Worker-12" prio=10 tid=0x09910c00 nid=0x12a0 in Object.wait() [0xb4026000]  
    16.    java.lang.Thread.State: TIMED_WAITING (on object monitor)  
    17.     at java.lang.Object.wait(Native Method)  
    18.     at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)  
    19.     - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)  
    20.     at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)  
    21.     at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)  
    22.   
    23. .......省略  
    24.   
    25. "Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000]  
    26.    java.lang.Thread.State: RUNNABLE  
    27.   
    28. "CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000]  
    29.    java.lang.Thread.State: RUNNABLE  
    30.   
    31. "Signal Dispatcher" daemon prio=10 tid=0x097e7400 nid=0xa9d runnable [0x00000000]  
    32.    java.lang.Thread.State: RUNNABLE  
    33.   
    34. "Finalizer" daemon prio=10 tid=0x097e4000 nid=0xa9c in Object.wait() [0xb4dd1000]  
    35.    java.lang.Thread.State: WAITING (on object monitor)  
    36.     at java.lang.Object.wait(Native Method)  
    37.     at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)  
    38.     - locked <0x6e2e02f8> (a java.lang.ref.ReferenceQueue$Lock)  
    39.     at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)  
    40.     at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)  
    41.   
    42. "Reference Handler" daemon prio=10 tid=0x097df400 nid=0xa9b in Object.wait() [0xb4e22000]  
    43.    java.lang.Thread.State: WAITING (on object monitor)  
    44.     at java.lang.Object.wait(Native Method)  
    45.     at java.lang.Object.wait(Object.java:502)  
    46.     at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)  
    47.     - locked <0x6e2e0098> (a java.lang.ref.Reference$Lock)  
    48.   
    49. "main" prio=10 tid=0x097b0400 nid=0xa99 runnable [0xbf8b9000]  
    50.    java.lang.Thread.State: RUNNABLE  
    51.     at org.eclipse.swt.internal.gtk.OS.Call(Native Method)  
    52.     at org.eclipse.swt.widgets.Display.sleep(Display.java:4069)  
    53.     at org.eclipse.ui.application.WorkbenchAdvisor.eventLoopIdle(WorkbenchAdvisor.java:364)  
    54.     at org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor.eventLoopIdle(IDEWorkbenchAdvisor.java:917)  
    55.     at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2697)  
    56.     at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2660)  
    57.     at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494)  
    58.     at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674)  
    59.     at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)  
    60.     at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667)  
    61.     at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)  
    62.     at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:123)  
    63.     at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)  
    64.     at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)  
    65.     at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)  
    66.     at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)  
    67.     at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)  
    68.     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    69.     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)  
    70.     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  
    71.     at java.lang.reflect.Method.invoke(Method.java:616)  
    72.     at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)  
    73.     at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)  
    74.     at org.eclipse.equinox.launcher.Main.run(Main.java:1410)  
    75.   
    76. "VM Thread" prio=10 tid=0x097dd800 nid=0xa9a runnable   
    77. "GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable  
    78.   
    79. "GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable  
    80.   
    81. "VM Periodic Task Thread" prio=10 tid=0x097ed400 nid=0xaa0 waiting on condition   
    82.   
    83. JNI global references: 2131  

     

    上面的stack trace一共可以拆解成5个部分。

    第一部分: Full thread dump identifier

    Java代码  收藏代码
    1. 2012-08-28 23:16:39  
    2. Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing):  

     可以看到dump时间,虚拟机的信息。

     

    第二部分: Java EE middleware, third party & custom application Threads

    Java代码  收藏代码
    1. "Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000]    
    2.    java.lang.Thread.State: TIMED_WAITING (on object monitor)    
    3.     at java.lang.Object.wait(Native Method)    
    4.     at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)    
    5.     - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)    
    6.     at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)    
    7.     at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)  

    此处是我们最为关心的地方,也是通过stack trace查找问题的地方,每个item的具体含义是

    -Thread name: "Worker-15"

    -线程优先级: prio=10

    -java线程的identifier:tid=0x09b7b400

    -native线程的identifier: nid=0x12f2

    -线程的状态: in Object.wait()  java.lang.Thread.State: TIMED_WAITING (on object monitor)  

    -线程栈起始地址:[0xb30f9000]  

     

    Java线程和Native线程,也就是tid和nid的区别?

    VM是加载并执行字节码的机器,这个处理不对应具体硬件,它完全由软件来实现。虚拟机并不是直接跑在宿主的cpu上,中间还隔着宿主的操作系统。

    虚拟机的职责是:翻译字节码,把它翻译成一系列的动作(内存操作)和系统调用(比如输入输出)。举个例子:当在java里请求与某台远程机器建立socket连接时,java虚拟机本身是不能完成这一工作的(协议栈是在操作系统内实现的),所以它需要系统调用。要明白这个,还需要知道JRE和JVM的关系。JRE是JVM的环境,一个应用程序就是一个JVM实例。一个机器上一般同时只有一个JRE环境,但是可以同时有多个JVM实例。不同的操作系统和CPU架构有不同的JRE。JRE包含了最基本的类库,当然包括和操作系统打交道的Native库,比如windows下的dll文件,linux下的so文件。JVM实例解析字节码的成JVM中的指令集,再通过Native方法进行操作系统层面的系统调用。下面的图能比较清楚的说明问题。


    JVM线程如何创建

    当然是通过Native库的 native方法。JVM的线程最终是通过操作系统的线程来完成系统调用的。针对Java开发者来说,发号施令的是JVM 线程,具体干藏活累活的却是操作系统线程。不同操作系统上,JVM创建本地线程依赖的native库也不同。具体可参考下面的的文章。http://jackyhongvip.iteye.com/blog/1338610

     

    JVM线程状态

    状态有Runnable、Wait on condition、Waiting for monitor entry 和 in Object.wait()。

    Runnable:不解释

    Wait on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写。如果网络数据没准备好,线程就等待在那里。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。

    Waiting for monitor entry 和 in Object.wait():这两种情况在多线程的情况下经常出现。Java是通过Monitor来实现线程互斥和协作(有些把Monitor直译成锁,我认为不妥,不是还有Lock嘛)。具体Monitor的深入理解见 http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html

    但是可以理解成Monitor是一个对象或者class所拥有的锁,每个对象和class有且仅有一个。见下图.


    每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。

    在 “ Entry Set”里面的线程都等待拿到Monitor,拿到了线程就成为了Runnable线程,否则就会一直处于处于 “waiting for monitor entry”。一段代码作为例子

    Java代码  收藏代码
    1. public class MyThread implements Runnable{    
    2.   
    3.      public void run() {    
    4.          synchronized(this) {    
    5.               for (int i = 0; i < 1; i--) {    
    6.                    System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);    
    7.               }    
    8.          }    
    9.     }    
    10.     public static void main(String[] args) {    
    11.         MyThread t1 = new MyThread();    
    12.          Thread ta = new Thread(t1, "A");    
    13.          Thread tb = new Thread(t1, "B");    
    14.          ta.start();    
    15.          tb.start();    
    16.     }   
    17.   
    18. }  

    大家一看就知道,B线程肯定是“千年老二“,永远拿不到Monitor了。

    对应的stack:

    Java代码  收藏代码
    1. "B" prio=10 tid=0x0969a000 nid=0x11d6 waiting for monitor entry [0x8bb22000]  
    2.    java.lang.Thread.State: BLOCKED (on object monitor)  
    3.     at org.marshal.MyThread.run(MyThread.java:7)  
    4.     - waiting to lock <0x94757078> (a org.marshal.MyThread)  
    5.     at java.lang.Thread.run(Thread.java:636)  
    6.   
    7. "A" prio=10 tid=0x09698800 nid=0x11d5 runnable [0x8bb73000]  
    8.    java.lang.Thread.State: RUNNABLE  
    9.     at java.io.FileOutputStream.writeBytes(Native Method)  
    10.     at java.io.FileOutputStream.write(FileOutputStream.java:297)  
    11.     at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)  
    12.     at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)  
    13.     - locked <0x947571b0> (a java.io.BufferedOutputStream)  
    14.     at java.io.PrintStream.write(PrintStream.java:449)  
    15.     - locked <0x94757190> (a java.io.PrintStream)  
    16.     at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:220)  
    17.     at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:290)  
    18.     at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:103)  
    19.     - locked <0x947572a0> (a java.io.OutputStreamWriter)  
    20.     at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)  
    21.     at java.io.PrintStream.write(PrintStream.java:494)  
    22.     - locked <0x94757190> (a java.io.PrintStream)  
    23.     at java.io.PrintStream.print(PrintStream.java:636)  
    24.     at java.io.PrintStream.println(PrintStream.java:773)  
    25.     - locked <0x94757190> (a java.io.PrintStream)  
    26.     at org.marshal.MyThread.run(MyThread.java:8)  
    27.     - locked <0x94757078> (a org.marshal.MyThread)  
    28.     at java.lang.Thread.run(Thread.java:636)  

       <0x94757078> 就是两个线程争夺的Monitor。

    在 “Wait Set”里面的线程都如饥似渴地等待拿到Monitor。他们是怎么进入到“Wait Set”的呢?当一个线程拿到了Monitor,但是在其他资源没有到位的情况下,调用同步锁对象(一般是synchronized()内的对象)的 wait() 方法,放弃了 Monitor,它就进入到了 “Wait Set”队列。只有当其他线程通过notify() 或者 notifyAll(),释放了同步锁后,这个线程才会有机会重新去竞争Monitor。在stack中,它表现的状态是in Object.wait()。修改上面的代码public class WaitThread implements Runnable{ 

    Java代码  收藏代码
    1. public void run() {    
    2.       synchronized(this) {   
    3.         try {  
    4.         this.wait();  
    5.     } catch (InterruptedException e) {  
    6.         // TODO Auto-generated catch block  
    7.         e.printStackTrace();  
    8.     }              
    9.       }    
    10.  }    
    11.  public static void main(String[] args) {    
    12.    WaitThread t1 = new WaitThread();    
    13.       Thread ta = new Thread(t1, "A");    
    14.       Thread tb = new Thread(t1, "B");    
    15.       ta.start();    
    16.       tb.start();            
    17.  }   

     对应的stack:

    Java代码  收藏代码
    1. "B" prio=10 tid=0x08173000 nid=0x1304 in Object.wait() [0x8baf2000]  
    2.    java.lang.Thread.State: WAITING (on object monitor)  
    3.     at java.lang.Object.wait(Native Method)  
    4.     - waiting on <0xa9cb50e0> (a org.marshal.WaitThread)  
    5.     at java.lang.Object.wait(Object.java:502)  
    6.     at org.marshal.WaitThread.run(WaitThread.java:8)  
    7.     - locked <0xa9cb50e0> (a org.marshal.WaitThread)  
    8.     at java.lang.Thread.run(Thread.java:636)  
    9.   
    10. "A" prio=10 tid=0x08171c00 nid=0x1303 in Object.wait() [0x8bb43000]  
    11.    java.lang.Thread.State: WAITING (on object monitor)  
    12.     at java.lang.Object.wait(Native Method)  
    13.     - waiting on <0xa9cb50e0> (a org.marshal.WaitThread)  
    14.     at java.lang.Object.wait(Object.java:502)  
    15.     at org.marshal.WaitThread.run(WaitThread.java:8)  
    16.     - locked <0xa9cb50e0> (a org.marshal.WaitThread)  
    17.     at java.lang.Thread.run(Thread.java:636)  

     A和B线程都进入了”wait set“。B线程也拿到过这个Monitor,因为A线程释放过了,这也验证上面的话,他们都在等待得而复失的<0xa9cb50e0>。

    基于我们经常讨论到的死锁问题,构造一段代码如下

    Java代码  收藏代码
    1. public class DeadThread implements Runnable{  
    2.       
    3.     private Object monitor_A = new Object();  
    4.       
    5.     private Object monitor_B = new Object();  
    6.       
    7.     public void  method_A(){  
    8.          synchronized(monitor_A) {   
    9.                synchronized(monitor_B) {   
    10.                    System.out.println(Thread.currentThread().getName()+" invoke method A");  
    11.                }                  
    12.            }          
    13.     }  
    14.       
    15.     public void  method_B(){  
    16.          synchronized(monitor_B) {   
    17.                synchronized(monitor_A) {   
    18.                    System.out.println(Thread.currentThread().getName()+" invoke method B");  
    19.                }                  
    20.            }          
    21.     }     
    22.   
    23.     public void run() {       
    24.         for(int i=0;i<1;i--){               
    25.             method_A();            
    26.             method_B();                        
    27.         }              
    28.     }  
    29.        
    30.   public static void main(String[] args) {    
    31.       DeadThread t1 = new DeadThread();    
    32.        Thread ta = new Thread(t1, "A");    
    33.        Thread tb = new Thread(t1, "B");    
    34.     
    35.        ta.start();    
    36.        tb.start();   
    37.   }   
    38. }  

      对应的stack:

    Java代码  收藏代码
    1. "B" prio=10 tid=0x0898d000 nid=0x269a waiting for monitor entry [0x8baa2000]  
    2.    java.lang.Thread.State: BLOCKED (on object monitor)  
    3.     at org.marshal.DeadThread.method_A(DeadThread.java:11)  
    4.     - waiting to lock <0xaa4d6f88> (a java.lang.Object)  
    5.     - locked <0xaa4d6f80> (a java.lang.Object)  
    6.     at org.marshal.DeadThread.run(DeadThread.java:28)  
    7.     at java.lang.Thread.run(Thread.java:636)  
    8.   
    9. "A" prio=10 tid=0x0898b800 nid=0x2699 waiting for monitor entry [0x8baf3000]  
    10.    java.lang.Thread.State: BLOCKED (on object monitor)  
    11.     at org.marshal.DeadThread.method_B(DeadThread.java:19)  
    12.     - waiting to lock <0xaa4d6f80> (a java.lang.Object)  
    13.     - locked <0xaa4d6f88> (a java.lang.Object)  
    14.     at org.marshal.DeadThread.run(DeadThread.java:29)  
    15.     at java.lang.Thread.run(Thread.java:636)  

     同时注意到,在stack trace尾部信息

    Java代码  收藏代码
    1. Found one Java-level deadlock:  
    2. =============================  
    3. "B":  
    4.   waiting to lock monitor 0x089615d8 (object 0xaa4d6f88, a java.lang.Object),  
    5.   which is held by "A"  
    6. "A":  
    7.   waiting to lock monitor 0x08962258 (object 0xaa4d6f80, a java.lang.Object),  
    8.   which is held by "B"  
    9.   
    10. Java stack information for the threads listed above:  
    11. ===================================================  
    12. "B":  
    13.     at org.marshal.DeadThread.method_A(DeadThread.java:11)  
    14.     - waiting to lock <0xaa4d6f88> (a java.lang.Object)  
    15.     - locked <0xaa4d6f80> (a java.lang.Object)  
    16.     at org.marshal.DeadThread.run(DeadThread.java:28)  
    17.     at java.lang.Thread.run(Thread.java:636)  
    18. "A":  
    19.     at org.marshal.DeadThread.method_B(DeadThread.java:19)  
    20.     - waiting to lock <0xaa4d6f80> (a java.lang.Object)  
    21.     - locked <0xaa4d6f88> (a java.lang.Object)  
    22.     at org.marshal.DeadThread.run(DeadThread.java:29)  
    23.     at java.lang.Thread.run(Thread.java:636)  
    24.   
    25. Found 1 deadlock.  

      stack中直接报告了Java级别的死锁,够智能吧。

     

    第三部分:HotSpot VM Thread

    Java代码  收藏代码
    1. "Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000]    
    2.    java.lang.Thread.State: RUNNABLE    
    3.     
    4. "CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000]    
    5.    java.lang.Thread.State: RUNNABLE   

     

    JVM管理的内部线程,这些内部线程都是来执行native操作的,可以不必太关注。

     

    第四部分: HotSpot GC Thread

    Java代码  收藏代码
    1. "GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable  
    2.   
    3. "GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable  

      当虚拟机打开了parallel GC,这些线程就会定期地GC清理。

     

    第五部分:JNI global references count

    Java代码  收藏代码
    1. JNI global references: 2131  

     JNI (Java Native Interface)全局引用也是受垃圾回收器管理。它的作用是防止回收到那些在native代码上还是被引用的,但是在java代码中却没有存活必要的引用。对于防止因为应用代码中直接使用native库或者第三方的一些监控工具的内存泄漏有非常大的帮助。

  • 相关阅读:
    学习winform第三方界面weiFenLuo.winFormsUI.Docking.dll
    C#中MySQL数据库的备份 还原 初始化
    winform学习笔记02
    mysql与sqlserver之间的关系转换
    mysql数据库使用
    python学习--导入自己的包
    thymeleaf 拼接 超链接
    @RequestParam与@PathVariable的区别
    ifram 实现左侧菜单,右侧显示内容
    Spring 整合Shiro:记住我
  • 原文地址:https://www.cnblogs.com/hushaojun/p/4323963.html
Copyright © 2011-2022 走看看