欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java常用命令及性能调优工具

程序员文章站 2022-07-14 16:38:07
...

1、Linux命令

1.1 top命令

Java常用命令及性能调优工具
top命令的输出可以分为上下两部分:系统统计信息和进程统计信息。

系统统计信息:
- 第一行:任务队列信息。等同于uptime命令

20:30:40 up 71 days, 21:36,  1 user,  load average: 0.15, 0.16, 0.13

系统当前时间、系统运行时间、当前登录用户数。load average表示系统的平均负载(1分钟内、5分钟内、15分钟内)。
- 第二行:进程统计信息。分别为总的进程数、运行中的进程数、睡眠进程数、停止的进程数以及僵尸进程数。

Tasks:  75 total,   1 running,  74 sleeping,   0 stopped,   0 zombie
  • 第三行:CPU统计信息。
Cpu(s):  0.4%us,  0.2%sy,  0.0%ni, 99.4%id,  0.1%wa,  0.0%hi,  0.0%si,  0.0%st

us:用户态CPU占用率、sy:内核态CPU占用率、ni:用户进程空间改变过优先级的进程CPU占用率、id:空闲CPU占用率、wa:等待输入输出的CPU时间百分比、hi:硬件中断请求、si:软件中断请求、st:CPU服务于软中断所耗费的时间总额。
- 第四行:内存统计信息。

Mem:   1922244k total,  1200496k used,   721748k free,   181508k buffers

依次表示物理内存总量、已使用内存量、空闲内存量、内核缓冲使用量。
- 第五行:交换区统计信息。

Swap:        0k total,        0k used,        0k free,   435204k cached

依次表示交换区总量、已使用交互区总量、空闲交换区总量、缓冲的交换区总量。

进程统计信息:
- PID:进程id
- USER:进程所有者的用户id
- PR:优先级
- NI:nice值。负值表示高优先级、正值表示低优先级
- VIRT:进程使用的虚拟内存总量。VIRT=SWAP+RES
- RES:进程使用的、未被换出的物理内存大小
- SHR:共享内存大小(KB)
- S:进程状态。R-运行、S-睡眠、D-不可中断的睡眠、T-跟踪/停止、Z-僵尸
- %CPU:上次更新到现在的CPU时间占用百分比
- %MEM:进程使用的物理内存百分比
- %TIME+:进程使用的CPU时间总计
- COMMAND:命令名

top常用子命令:
- h:帮助
- k:终止一个进程
- c:切换显示完整的命令行
- M:按照内存大小排序
- P:按照CPU占用百分比排序

1.2 sar命令

sar命令也是Linux系统中重要的性能检测工具之一,可周期性的对内存和CPU的使用情况进行采样。如下:

sar 1 5

表示每隔1秒采样1次,共采样5次。

Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)

02:40:35 PM     CPU     %user     %nice   %system   %iowait    %steal     %idle
02:40:36 PM     all      0.99      0.00      0.99      0.00      0.00     98.02
02:40:37 PM     all      0.00      0.00      0.00      0.00      0.00    100.00
02:40:38 PM     all      1.00      0.00      0.00      0.00      0.00     99.00
02:40:39 PM     all      0.00      0.00      0.00      0.00      0.00    100.00
02:40:40 PM     all      0.00      0.00      0.00      0.00      0.00    100.00
Average:        all      0.40      0.00      0.20      0.00      0.00     99.40

option选项:
- -A:所有报告。
- -u:CPU利用率。默认选项。
- -d:磁盘使用情况。
- -b:I/O使用情况。
- -q:查看队列长度。
- -r:内存使用情况。
- -n:查看网络信息统计。【ALL】
- -o:将采样结果输出到文件

1.3 vmstat命令

vmstat命令同样也是Linux系统中重要的性能检测工具之一,不仅可周期性的对内存、CPU进行采样,还可以对swap使用进行采样。

vmstat 1 5

表示每隔1秒采样一次,共采样5次。

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 401032 183320 732700    0    0     3     2    3    6  0  0 99  0  0    
 0  0      0 401016 183320 732700    0    0     0     0  234  512  0  1 99  0  0    
 0  0      0 401016 183320 732700    0    0     0     0  220  495  0  0 100  0  0   
 0  0      0 401016 183320 732700    0    0     0    32  240  518  1  0 99  0  0    
 0  0      0 401016 183320 732700    0    0     0     0  244  511  0  0 100  0  0
  • procs
    • r:等待运行的进程数
    • b:处在非中断睡眠状态的进程数
  • memory
    • swpd:虚拟内存使用情况(KB)
    • free:空闲内存大小(KB)
    • buff:表示块设备(block device)所占用的缓存页,包括:直接读写块设备、以及文件系统元数据(metadata),比如SuperBlock所使用的缓存页(KB)
    • cache:表示普通文件数据所占用的缓存页
  • swap
    • si:从磁盘交换到内存的交换页数量(KB/秒)
    • so:从内存交换到磁盘的交换页数量(KB/秒)
  • io
    • bi:发送到块设备的块数(块/秒)
    • bo:从块设备接收到的块数(块/秒)
  • system
    • in:每秒中断数
    • cs:每秒上下文切换次数
  • cpu
    • us:用户态CPU占用率
    • sy:内核态CPU占用率
    • id:空闲CPU占用率
      -wa:等待输入输出的CPU时间百分比
    • st:CPU服务于软中断所耗费的时间总额

1.4 iostat命令

iostat可以提供详尽的I/O信息。

iostat 1 2

表示每隔1秒采样1次,共采样2次。

Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.42    0.00    0.17    0.05    0.00   99.36

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
vda               0.49         5.86         4.35   39755548   29531688
vdb               0.00         0.00         0.00       1392          0

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.00    0.00    0.00    0.00    0.00   99.00

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
vda               0.00         0.00         0.00          0          0
vdb               0.00         0.00         0.00          0          0
  • tps:该设备每秒的传输次数
  • Blk_read/s:每秒从设备读取的数据量
  • Blk_wrtn/s:每秒向设备写入的数据量
  • Blk_read:读取的总数据量
  • Blk_wrtn:写入的总数据量

1.5 pidstat命令

pidstat也是一个功能强大的性能检测工具。不仅可以检测进程的性能,还可以检测线程的性能。

1.5.1 CPU使用率监控

下面的程序中,开启了3个线程,其中一个大量占用CPU,其他2个线程处于空闲状态。

public class CPUMain {
    public static class BusyCPUTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                double i = Math.random() * Math.random();
            }
        }
    }
    public static class LazyCPUTask implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    TimeUnit.SECONDS.sleep(1);
                }
            } catch (Exception e) {
                // do nothing
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new BusyCPUTask()).start();
        new Thread(new LazyCPUTask()).start();
        new Thread(new LazyCPUTask()).start();
    }
}
  • 1、使用jps -l找到该Java程序的PID:
[aaa@qq.com ~]# jps -l
19077 sun.tools.jps.Jps
19064 command.CPUMain
17338 org.elasticsearch.bootstrap.Elasticsearch
17851 org.jruby.Main
  • 2、使用pidstat命令输出该程序的CPU使用情况:
[root@- ~]# pidstat -p 19064 -u 1 3
Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)
05:49:01 PM       PID    %usr %system  %guest    %CPU   CPU  Command
05:49:02 PM     19064   99.00    0.00    0.00   99.00     0  java
05:49:03 PM     19064  100.00    0.00    0.00  100.00     0  java
05:49:04 PM     19064   99.00    0.00    0.00   99.00     0  java
Average:        19064   99.33    0.00    0.00   99.33     -  java

-p 指定进程的ID,-u 对CPU使用率进行监控;每隔1秒采样1次,共采样3次。
- 3、使用-t参数找出最占CPU的线程

[aaa@qq.com ~]# pidstat -p 19064  -u -t 1 1
Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)
05:56:00 PM      TGID       TID    %usr %system  %guest    %CPU   CPU  Command
05:56:01 PM     19064         -   99.00    0.00    0.00   99.00     0  java
05:56:01 PM         -     19064    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19065    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19066    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19067    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19068    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19069    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19070    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19071    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19072    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19073    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19074  100.00    0.00    0.00  100.00     0  |__java
05:56:01 PM         -     19075    0.00    0.00    0.00    0.00     0  |__java
05:56:01 PM         -     19076    0.00    0.00    0.00    0.00     0  |__java
... ...

可以看到, 19074 这个线程占用了大量CPU。
备注:上述2和3两个过程可以使用top -p 19064 -H命令查出哪个线程占用大量CPU,如下:

[aaa@qq.com ~]# top -p 19064 -H
top - 17:57:41 up 78 days, 19:03,  3 users,  load average: 1.00, 0.86, 0.55
Tasks:  13 total,   1 running,  12 sleeping,   0 stopped,   0 zombie
Cpu(s): 99.7%us,  0.3%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1922244k total,  1584308k used,   337936k free,   185344k buffers
Swap:        0k total,        0k used,        0k free,   776028k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                        
19064 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19065 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.07 java                                                                                                                            
19066 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19067 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19068 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19069 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19070 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19071 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19072 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java                                                                                                                            
19073 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.12 java                                                                                                                            
19074 root      20   0 2414m  23m  11m R 99.6  1.3   9:09.31 java                                                                                                                            
19075 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.01 java                                                                                                                            
19076 root      20   0 2414m  23m  11m S  0.0  1.3   0:00.00 java

得到的结果同样是19074 这个线程。
- 4、jstack定位线程栈
jstack 19064 > jstack.log
- 5、查看19074线程情况
通过使用命令printf %x 19074得到19074的16进制:4a82
查看4a82线程:

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007fae380fa800 nid=0x4a82 runnable [0x00007fae3c551000]
   java.lang.Thread.State: RUNNABLE
        at command.CPUMain$BusyCPUTask.run(CPUMain.java:14)
        at java.lang.Thread.run(Thread.java:745)

结论:可以定位到线程在执行CPUMain.java:14占用了大量CPU。

1.5.2 I/O监控

下面的程序中,开启了3个线程,其中一个大量占用I/O,其他2个线程处于空闲状态。

public class IOMain {
    public static class BusyIOTask implements Runnable {
        @Override
        public void run() {
            try {
                FileOutputStream fos;
                FileInputStream fis;
                while (true) {
                    fos = new FileOutputStream(new File("temp"));
                    for (int i = 0; i < 1000; i++) {
                        fos.write(i);           // 写操作
                    }
                    fos.close();
                    fis = new FileInputStream(new File("temp"));
                    while (fis.read() != -1);   // 读操作
                    fis.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static class LazyIOTask implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    TimeUnit.SECONDS.sleep(1);
                }
            } catch (Exception e) {
                // do nothing
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new IOMain.BusyIOTask()).start();
        new Thread(new IOMain.LazyIOTask()).start();
        new Thread(new IOMain.LazyIOTask()).start();
    }
}
  • 1、使用jps -l找到该Java程序的PID:
[aaa@qq.com ~]# jps -l
17338 org.elasticsearch.bootstrap.Elasticsearch
17851 org.jruby.Main
19323 sun.tools.jps.Jps
19310 command.IOMain
  • 2、使用pidstat命令输出该程序的各个线程的I/O使用情况:
[aaa@qq.com ~]# pidstat -p 19310 -d -t 1 3
Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)
06:30:13 PM      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
06:30:14 PM     19310         -      0.00   3482.83   1741.41  java
06:30:14 PM         -     19310      0.00      0.00      0.00  |__java
06:30:14 PM         -     19311      0.00      0.00      0.00  |__java
06:30:14 PM         -     19312      0.00      0.00      0.00  |__java
06:30:14 PM         -     19313      0.00      0.00      0.00  |__java
06:30:14 PM         -     19314      0.00      0.00      0.00  |__java
06:30:14 PM         -     19315      0.00      0.00      0.00  |__java
06:30:14 PM         -     19316      0.00      0.00      0.00  |__java
06:30:14 PM         -     19317      0.00      0.00      0.00  |__java
06:30:14 PM         -     19318      0.00      0.00      0.00  |__java
06:30:14 PM         -     19319      0.00      0.00      0.00  |__java
06:30:14 PM         -     19320      0.00   3478.79   1741.41  |__java
06:30:14 PM         -     19321      0.00      0.00      0.00  |__java
06:30:14 PM         -     19322      0.00      0.00      0.00  |__java
... ...
  • 3、定位线程栈
    同样地使用jstack命令,导出该程序的线程栈,查找nid=19320(0x4b78)的线程,即可定位问题。

1.5.3 内存监控

使用pidstat命令,还可以监视指定进程的内存的使用情况。

[aaa@qq.com test]# pidstat -p 17338 -r 1 3
Linux 2.6.32-573.22.1.el6.x86_64 (-)    03/14/2017  _x86_64_    (1 CPU)

06:36:36 PM       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
06:36:37 PM     17338      0.00      0.00 2677708 280504  14.59  java
06:36:38 PM     17338      0.00      0.00 2677708 280504  14.59  java
06:36:39 PM     17338      0.00      0.00 2677708 280504  14.59  java
Average:        17338      0.00      0.00 2677708 280504  14.59  java
  • minflt/s:该进程每秒minor faults(不需要从磁盘中调出内存页)的总数
  • majflt/s:该进程每秒major faults(需要从磁盘中调出内存页)的总数
  • VSZ:该进程使用的虚拟内存大小(KB)
  • RSS:该进程使用的物理内存大小(KB)
  • %MEM:内存占用率

2、JDK命令

2.1 jps命令

jps命令类似于Linux的ps,只不过ps是查看Linux系统的进程,jps只是列出当前用户启动的Java进程
- jps

[aaa@qq.com ~]# jps
17338 Elasticsearch
17851 Main
21166 Jps
  • jps -q:只输出进程id
  • jps -m:输出传递给Java Main函数的参数
  • jps -l:输出Main函数的完整路径
  • jps -v:输出传递给JVM的参数

2.2 jstat命令

jstat命令用于观察Java程序的运行时工具。

Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

option可选项:
- -class:显示ClassLoader的相关信息

[aaa@qq.com ~]# jstat -class -t 17338
Timestamp       Loaded  Bytes  Unloaded  Bytes     Time   
      4302040.9   8482 15664.4       12    12.0       7.94

Loaded表示载入类的数量、Bytes表示载入类的大小、Unloaded表示卸载类的数量、Bytes表示卸载类的大小、Time表示在加载及卸载类上所花的时间。

  • -compiler:显示JIT编译的相关信息
[aaa@qq.com ~]# jstat -compiler -t 17338
Timestamp       Compiled Failed Invalid   Time   FailedType FailedMethod
      4312097.9    12812      0       0    73.32          0

Complied表示编译任务执行的次数、Failed表示编译失败的次数、Invalid表示不可用的次数、Time表示编译的总耗时、FailedType表示最后一次编译失败的类型、FailedMethod表示最后一次编译失败的类名和方法名。

  • -gc:显示与GC相关的堆信息
[aaa@qq.com ~]# jstat -gc -t 17338
Timestamp        S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
      4312491.0 8512.0 8512.0  76.1   0.0   68160.0  15675.5   439104.0   18409.8   47780.0 47055.7 5600.0 5363.6    644    4.077   4      0.176    4.253
  • S0C:S0(From)的大小(KB)
  • S1C:S1(To)的大小(KB)
  • S0U:S0(From)已使用的大小(KB)
  • S1U:S1(To)已使用的大小(KB)
  • EC:Eden区的大小(KB)
  • EU:Eden已使用的大小(KB)
  • OC:老年代大小(KB)
  • OU:老年代已使用的大小(KB)
  • MC:方法区大小(KB)
  • MU:方法区已使用大小(KB)
  • CCSC:压缩类空间大小(KB)
  • CCSU:压缩类空间已使用大小(KB)
  • PC:永久区大小(KB)
  • PU:永久区已使用大小(KB)
  • YGC:新生代GC次数
  • YGCT:新生代GC耗时
  • FGC:Full GC次数
  • FGCT:Full GC耗时
  • GCT:GC总耗时

    • -gccapacity:显示各个代的容量及使用情况
[aaa@qq.com ~]# jstat -gccapacity -t 17338
Timestamp        NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC 
      4313185.9  85184.0  85184.0  85184.0 8512.0 8512.0  68160.0   439104.0   439104.0   439104.0   439104.0      0.0 1091584.0  47780.0      0.0 1048576.0   5600.0    644     4

-gc相比,不仅输出了各个代当前的大小,还输出了各个代的最小、最大值。
- NGCMN:新生代最小值(KB)
- NGCMX:新生代最大值(KB)
- NGC:当前新生代大小(KB)
- OGCMN:老年代最小值(KB)
- OGCMX:老年代最大值(KB)
- PGCMN:永久区最小值(KB)
- PGCMX:永久区最大值(KB)

  • -gccause:显示垃圾收集相关信息(同gcutil),同时显示最后一次或当前正在发生的垃圾收集的诱发原因
[aaa@qq.com ~]# jstat -gccause -t 17338
Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
      4313692.2   0.89   0.00  43.07   4.19  98.48  95.78    644    4.077     4    0.176    4.253 Allocation Failure   No GC
  • LGCC:最近一次GC的的原因
  • GCC:当前GC的原因

    • -gcnew:显示新生代信息
[aaa@qq.com ~]# jstat -gcnew -t 17338
Timestamp        S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
      4314215.7 8512.0 8512.0   76.1    0.0  6   6 4256.0  68160.0  33355.0    644    4.077
  • TT:新生代对象晋升到老年代对象的年龄
  • MTT:新生代对象晋升到老年代对象的年龄最大值
  • DSS:所需的幸存区大小

    • -gcnewcapacity:显示新生代容量及使用情况
[aaa@qq.com ~]# jstat -gcnewcapacity -t 17338
Timestamp         NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
      4314357.1    85184.0    85184.0    85184.0   8512.0   8512.0   8512.0   8512.0    68160.0    68160.0   644     4
  • S0CMX:S0区的最大值
  • S1CMX:S1区的最大值
  • ECMX:Eden区的最大值

    • -gcold:显示老年代和永久代的信息
[aaa@qq.com ~]# jstat -gcold -t 17338
Timestamp          MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
      4314463.2  47780.0  47055.7   5600.0   5363.6    439104.0     18409.8    644     4    0.176    4.253
  • -gcoldcapacity:显示老年代容量
[aaa@qq.com ~]# jstat -gcoldcapacity -t 17338
Timestamp          OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
      4314490.9    439104.0    439104.0    439104.0    439104.0   644     4    0.176    4.253
  • -gcutil:显示垃圾收集信息
[aaa@qq.com ~]# jstat -gcutil -t 17338
Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
      4314594.9   0.89   0.00  52.34   4.19  98.48  95.78    644    4.077     4    0.176    4.253
  • -printcompilation:输出HotSpot编译方法的统计
[aaa@qq.com ~]# jstat -printcompilation -t 17338
Timestamp       Compiled  Size  Type Method
      4314622.9    12827    173    1 org/elasticsearch/cluster/routing/allocation/decider/AllocationDeciders canRebalance

其他选项:
- -t:在输出信息前加入一个时间戳,显示程序的运行时间
- -h:在周期性数据输出时,输出多少行数据后,跟着输出一个表头信息
- interval:指定输出统计数据的周期(毫秒)
- count:指定一共输出多少次数据

2.3 jinfo命令

jinfo可以查看正在运行的Java程序的JVM参数,并且支持运行时修改个别参数。

jinfo [option] <pid>

option可选项:
- -flag to print the value of the named VM flag,打印指定JVM的参数值
- -flag [+|-] to enable or disable the named VM flag,设置指定JVM参数的boolean值
- -flag = to set the named VM flag to the given value,设置指定JVM参数值
- -flags to print VM flags,打印JVM的参数值
- -sysprops to print Java system properties,打印Java系统的属性信息
- to print both of the above,打印flags和syspros

2.4 jmap命令

jmap命令能生成Java应用程序的堆快照和对象的统计信息。

jmap -histo 17338 > jmap.log
 num     #instances         #bytes  class name
----------------------------------------------
   1:        119627       16888576  [C
   2:         74845        8336640  [B
   3:         14991        3763272  [I
   4:         66990        3215520  java.lang.management.MemoryUsage
   5:         32973        2374056  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask
   6:         42965        2055352  [Ljava.lang.Object;
   7:         81756        1962144  java.lang.String
   8:          9035         994824  java.lang.Class
   9:          6709         858752  sun.nio.fs.UnixFileAttributes
  10:         24718         790976  sun.nio.fs.UnixPath
  ... ...
3729:             1             16  sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total       1077805       61629024

上述命令输出了内存中实例的数量和大小。

生成堆快照信息:

jmap -dump:format=b,file=heap.hprof 17338

2.5 jhat命令

jhat命令可以分析Java程序的堆快照。

[aaa@qq.com ~]# jhat heap.hprof 
Reading from heap.hprof...
Dump file created Wed Mar 15 15:42:02 CST 2017
Snapshot read, resolving...
Resolving 1183100 objects...
Chasing references, expect 236 dots............................................................................................................................................................................................................................................
Eliminating duplicate references............................................................................................................................................................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

可以通过浏览器访问7000端口查看堆快照信息。

2.6 jstack命令

用于输出Java应用程序的线程栈信息。

public class DeadLockMain {
    private static String A = "A";
    private static String B = "B";

    public void deadLock() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (A) {
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("thread1");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("thead2");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }

    public static void main(String[] args) {
        new DeadLockMain().deadLock();
    }
}

上述代码是一个简单的会发生死锁的例子,两个线程分别持有A和B,并分别请求B和A,导致死锁产生。
使用jstack打印上述进程的线程栈信息,部分输出如下:

"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f0ff410b000 nid=0x56d9 waiting for monitor entry [0x00007f0fe4bfa000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at command.DeadLockMain$2.run(DeadLockMain.java:33)
    - waiting to lock <0x00000000e2a77cc0> (a java.lang.String)
    - locked <0x00000000e2a77cf0> (a java.lang.String)
    at java.lang.Thread.run(Thread.java:745)

"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f0ff40fb000 nid=0x56d8 waiting for monitor entry [0x00007f0fe4cfb000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at command.DeadLockMain$1.run(DeadLockMain.java:23)
    - waiting to lock <0x00000000e2a77cf0> (a java.lang.String)
    - locked <0x00000000e2a77cc0> (a java.lang.String)
    at java.lang.Thread.run(Thread.java:745)




Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f0fd8004e28 (object 0x00000000e2a77cc0, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f0fd80062c8 (object 0x00000000e2a77cf0, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at command.DeadLockMain$2.run(DeadLockMain.java:33)
    - waiting to lock <0x00000000e2a77cc0> (a java.lang.String)
    - locked <0x00000000e2a77cf0> (a java.lang.String)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at command.DeadLockMain$1.run(DeadLockMain.java:23)
    - waiting to lock <0x00000000e2a77cf0> (a java.lang.String)
    - locked <0x00000000e2a77cc0> (a java.lang.String)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

从上述输出来看,很容易找到死锁,并且可以看到发生死锁的两个线程以及两个线程的持有和等待的对象。

相关标签: java 性能