zoukankan      html  css  js  c++  java
  • jstack找出最消耗资源的线程 并定位代码

    Java常用命令(一) jps、jstack、jmap

    一、jps

    jps由jdk1.5提供,用于查看当前用户下的java进程的pid及基本信息

    1、jps -help

    jps的帮助命令,可用jps -h代替:
    这里写图片描述

    2、jps -m

    查看进程pid及main方法参数:
    这里写图片描述
    图中 5940 是我的eclipse进程;18648是jps进程,他的main方法参数就是-m;27800是我启动的hbuilder软件;47852是我运行的测试函数,参数是zdgHK

    3、jps -q

    仅显示pid:
    这里写图片描述

    4 、jps -v

    查看pid及JVM参数:
    这里写图片描述

    5、 jps -l

    查看pid及程序所在包名:
    这里写图片描述
    图中29852就是我运行的测试Java程序。

    二、jstack

    使用jstack可查看指定进程(pid)的堆栈信息,用以分析线程情况:
    NEW:未启动的。不会出现在Dump中。
    RUNNABLE:在虚拟机内执行的。
    BLOCKED:受阻塞并等待监视器锁。
    WATING:无限期等待另一个线程执行特定操作。
    TIMED_WATING:有时限的等待另一个线程的特定操作。
    TERMINATED:已退出的。

    1、jstack -h

    帮助命令:
    这里写图片描述

    2、jstack [-l][-m][-F] pid

    -l:长列表,打印锁的附加信息;
    -m:打印java和native c/c++框架的所有栈信息;
    -F:没有响应的时候强制打印栈信息;

    3、例

    首先通过jps查看进程pid:
    这里写图片描述
    然后通过jstack 55872 打印堆栈信息:
    这里写图片描述
    图中仅是一部分信息截图,可以看到当前主线程状态是TIMED_WATING,在程序第6行:
    这里写图片描述

    4、线程死锁查看:

    程序:

    public class JpsTest {
        public static void main(String[] args) throws InterruptedException {
            //创建资源
            final Object a = new Object();
            final Object b = new Object();
            //启动线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //获取a的锁
                    synchronized (a) {
                        try {
                            System.out.println("i'm t1");
                            //等待一会儿,确保下一个线程获得另一个资源对象锁
                            Thread.sleep(100);
                            //获取b的锁
                            synchronized (b) {
                                System.out.println("t1------");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            //启动线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //获取b的锁
                    synchronized (b) {
                        try {
                            System.out.println("i'm t2");
                            //等待一会儿,确保下一个线程获得另一个资源对象锁
                            Thread.sleep(100);
                            //获取a的锁
                            synchronized (a) {
                                System.out.println("t2------");
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

    程序中两个线程分别持有对方所需资源的锁并等待对方释放导致死锁。
    查看jstack打印信息:
    这里写图片描述
    可以看到图中第一行显示发现了线程死锁,Thread-1等待资源 - waiting to lock <0x00000000eb4c0bf8> (a java.lang.Object),且锁住了资源 - locked <0x00000000eb4c0c08> (a java.lang.Object),Thread2则与之相反。

    3、jmap与jhat

    查看堆内存使用情况:
    jmap -heap pid:通过可查看堆内存的配置情况及使用情况
    jmap -histo pid:统计对象的创建数量
    jmap -dump:format=b,file=heapDump pid:生成dump文件与jhat配合使用
    jhat -port xxxx heapDump:浏览器访问localhost:xxxx即可查看dump
    例:
    程序(程序简陋,忽略细节):

    public class JmapTest {
        public static void main(String[] args) throws InterruptedException {
            JmapTest test = new JmapTest(300);
            fun(test);
            System.out.println(test.a);
        }
    
        private JmapTest next;
        private Integer a;
        public JmapTest(int a) {
            this.a = a;
        }
        //通过向一个链表递归添加对象
        public static void fun(JmapTest m) throws InterruptedException {
            System.out.println(m.a);
            m.next = new JmapTest(++m.a);
            //避免过早发送内存溢出
            Thread.sleep(1000);
            fun(m.next);
        }
    }

    首先通过使用jps -l获得pid,再通过jmap -heap pid查看堆内存配置及使用情况:
    配置信息:
    这里写图片描述
    使用情况:
    这里写图片描述
    接下来通过jmap -histo pid查看对象创建数量:
    这里写图片描述
    图中我们得程序已经创建了401个实例对象了。
    通过 jmap -dump:format=b,file=heapDump pid 生成heapDump文件:
    这里写图片描述
    这样文件已经创建成功,再通过jhat -port xxxx heapDump 启动一个监听程序查看文件:
    这里写图片描述
    程序已经启动,接下来在浏览器查看:
    这里写图片描述

     

    _______________________________________________________________________

    jstack找出最消耗资源的线程 并定位代码

    jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。

    第一步先找出Java进程ID,服务器上的Java应用名称为mrf-center:

    root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep
    root     21711     1  1 14:47 pts/3    00:02:10 java -jar mrf-center.jar
    得到进程ID为21711,第二步找出该进程内最耗费CPU的线程,可以使用
    1)ps -Lfp pid
    2)ps -mp pid -o THREAD, tid, time
    3)top -Hp pid
    用第三个,输出如下:

    TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程,用

    printf "%x
    " 21742

    得到21742的十六进制值为54ee,下面会用到。

    OK,下一步终于轮到jstack上场了,它用来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep,如下:

    root@ubuntu:/# jstack 21711 | grep 54ee
    "PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()

    可以看到CPU消耗在PollIntervalRetrySchedulerThread这个类的Object.wait(),我找了下我的代码,定位到下面的代码:

    // Idle wait
    getLog().info("Thread [" + getName() + "] is idle waiting...");
    schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
    long now = System.currentTimeMillis();
    long waitTime = now + getIdleWaitTime();
    long timeUntilContinue = waitTime - now;
    synchronized(sigLock) {
      try {
        if(!halted.get()) {
          sigLock.wait(timeUntilContinue);
        }
      } 
      catch (InterruptedException ignore) {
      }
    }

    它是轮询任务的空闲等待代码,上面的sigLock.wait(timeUntilContinue)就对应了前面的Object.wait()。

    _____________________________________________________________________________________________________________________

    jps 、jstack命令详解

    一、jps命令shi yong

    jps是jdk提供的一个查看当前java进程的小工具, 可以看做是JavaVirtual Machine Process Status Tool的缩写。非常简单实用。

           命令格式:jps [options ] [ hostid ] 

           [options]选项 :
               -q:仅输出VM标识符,不包括classname,jar name,arguments in main method 
              -m:输出main method的参数 
               -l:输出完全的包名,应用主类名,jar的完全路径名 
              -v:输出jvm参数 
             -V:输出通过flag文件传递到JVM中的参数(.hotspotrc文件或-XX:Flags=所指定的文件 
             -Joption:传递参数到vm,例如:-J-Xms512m

            [hostid]:

              [protocol:][[//]hostname][:port][/servername]

            命令的输出格式 :
                lvmid [ [ classname| JARfilename | "Unknown"] [ arg* ] [ jvmarg* ] ]

    1)jps

    2)jps –l:输出主类或者jar的完全路径名

    3)jps –v :输出jvm参数

    4)jps –q :仅仅显示Java进程号

     

    二、jstack

    jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式:

    jstack [-l] pid

    如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

    2、命令格式
    jstack [ option ] pid
    jstack [ option ] executable core
    jstack [ option ] [server-id@]remote-hostname-or-IP

    3、常用参数说明

    1)、options: 

    executable Java executable from which the core dump was produced.

    (可能是产生core dump的java可执行程序)

    core 将被打印信息的core dump文件

    remote-hostname-or-IP 远程debug服务的主机名或ip

    server-id 唯一id,假如一台主机上多个远程debug服务 

    2)、基本参数:

    -F当’jstack [-l] pid’没有相应的时候强制打印栈信息

    -l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.

    -m打印java和native c/c++框架的所有栈信息.

    -h | -help打印帮助信息

    pid 需要被打印配置信息的java进程id,可以用jps查询.

    4、使用示例

  • 相关阅读:
    在luogu上嫖到了一张感觉很NB的图
    luoguP6028算术 题解(推柿子+整除分块+调和级数)
    notebook
    不氵的 0xd
    点分治&&DSU on tree学习笔记
    洛谷10月月赛2T1题解
    概率与期望题库题目整理
    TiDB-TiUP工具使用
    TiDB-单机学习环境部署(4.X版本)
    DB-异构数据库迁移工具
  • 原文地址:https://www.cnblogs.com/kelelipeng/p/14302616.html
Copyright © 2011-2022 走看看