版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013310517/article/details/80990924

查看Java进程:jps

用法介绍 
 
jps命令:显示所有进程号和短的类名称 
 
Jps –q 命令:只显示进程号 
 
Jps –l 用于传输主函数的完整路径 
 
Jps –v 显示传递给Java虚拟机的参数(感觉这个命令才是完美,把虚拟机的一些参数全都打印出来) 

查看线程堆栈命令:jstack命令

Jstack命令主要用来查看Java线程的调用堆栈的,可以用来分析线程问题(如死锁)。谈到线程,在Java里面,线程一共有6中状态

  • New 新建 ————- 不会出现在dump中
  • Runnable 正在运行中——–在虚拟机内执行
  • Blocked 阻塞————受阻塞,并等待监视器锁
  • Waiting 等待————无限期等待另一个线程执行特定操作
  • Timed_waiting 超时等待————有时限等待另一个线程的操作
  • Terminated 终止/结束————已退出的

Monitor 
在多线程的 JAVA程序中,实现线程之间的同步,就要说说 Monitor。 Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 monitor。下 面这个图,描述了线程和 Monitor之间关系,以 及线程的状态转换图: 

进入区(Entrt Set):

表示线程通过synchronized要求获取对象的锁。如果对象未被锁住,则迚入拥有者;否则则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。

拥有者(The Owner):

表示某一线程成功竞争到对象锁。

等待区(Wait Set):

表示线程通过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。

从图中可以看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是 “in Object.wait()”。 先看 “Entry Set”里面的线程。我们称被 synchronized保护起来的代码段为临界区。当一个线程申请进入临界区时,它就进入了 “Entry Set”队列。对应的 code就像:

synchronized(obj) {
......... }
  • 1
  • 2
  • 3
  • 4

调用修饰 
表示线程在方法调用时,额外的重要的操作。线程Dump分析的重要信息。修饰上方的方法调用。 
locked <地址> 目标:使用synchronized申请对象锁成功,监视器的拥有者。 
waiting to lock <地址> 目标:使用synchronized申请对象锁未成功,在迚入区等待。 
waiting on <地址> 目标:使用synchronized申请对象锁成功后,释放锁幵在等待区等待。 
parking to wait for <地址> 目标

locked

at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通过synchronized关键字,成功获取到了对象的锁,成为监视器的拥有者,在临界区内操作。对象锁是可以线程重入的。

waiting to lock

at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo
  • 1
  • 2
  • 3
  • 4
  • 5

通过synchronized关键字,没有获取到了对象的锁,线程在监视器的进入区等待。在调用栈顶出现,线程状态为Blocked。

waiting on

at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

通过synchronized关键字,成功获取到了对象的锁后,调用了wait方法,进入对象的等待区等待。在调用栈顶出现,线程状态为WAITING或TIMED_WATING。

parking to wait for 
park是基本的线程阻塞原语,不通过监视器在对象上阻塞。随concurrent包会出现的新的机制,不synchronized体系不同。

线程动作 
线程状态产生的原因 
runnable:状态一般为RUNNABLE。 
in Object.wait():等待区等待,状态为WAITING或TIMED_WAITING。 
waiting for monitor entry:进入区等待,状态为BLOCKED。 
waiting on condition:等待区等待、被park。 
sleeping:休眠的线程,调用了Thread.sleep()。

Wait on condition 该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。 最常见的情况就是线程处于sleep状态,等待被唤醒。 常见的情况还有等待网络IO:在java引入nio之前,对于每个网络连接,都有一个对应的线程来处理网络的读写操作,即使没有可读写的数据,线程仍然阻塞在读写操作上,这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力。在 NewIO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高。 正等待网络读写,这可能是一个网络瓶颈的征兆。因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几 乎消耗了所有的带宽,仍然有大量数据等待网络读 写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达。所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目,如果很明显超过了所在网络带宽的限制 ; 观察 cpu的利用率,如果系统态的 CPU时间,相对于用户态的 CPU时间比例较高;如果程序运行在 Solaris 10平台上,可以用 dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈。(来自http://www.blogjava.net/jzone/articles/303979.html

jstack 命令详解 
 
简单介绍:

F当’jstack [-l] pid’没有相应的时候强制打印栈信息 -l长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表. -m打印java和native c/c++框架的所有栈信息. -h | -help打印帮助信息 pid 需要被打印配置信息的java进程id,可以用jps查询.

第一个实战代码:

/**
* Created by Cser_W on 2018/7/10.
*/
public class JstackDemo {
public static void main(String[] args){
while (true) {
//do nothing
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

先利用 jps 查看进程号 
 
利用jstack 进程号查看线程堆栈信息,如果发现自己写的代码一直处于Runnable状态,这有很大可能是自己写了个死循环。 
第二个实战代码

/**
* Created by Cser_W on 2018/7/10.
*/
public class JstackDemo1 {
public static void main(String[] args){
Thread thread = new Thread(new Thread1());
thread.start();
}
}
class Thread1 extends Thread {
@Override
public void run(){
while (true) {
System.out.println(1);
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17


我们能看到: 
线程的状态: WAITING 线程的调用栈 线程的当前锁住的资源: < < <0x00000000da380ee0>>> 线程当前等待的资源:< < <0x00000000da380ee0>>>

为什么同时锁住的等待同一个资源: 
线程的执行中,先获得了这个对象的 Monitor(对应于 locked < <0x00000000da380ee0>>)。当执行到 obj.wait(), 线程即放弃了 Monitor的所有权,进入 “wait set”队列(对应于 waiting on < <0x00000000da380ee0>> )。

死锁模拟实战

package com.wxy.test;

/**
* Created by Cser_W on 2018/7/10.
*/
public class JstackDemo2 {
public static void main(String[] args){
Thread thread1 = new Thread(new DeadLockClass(true));
Thread thread2 = new Thread((new DeadLockClass(false)));
thread1.start();
thread2.start();
}
}
class DeadLockClass implements Runnable {
public boolean flag;
DeadLockClass(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
while (true) {
synchronized (Suo.o1) {
System.out.println("o1" + Thread.currentThread().getName());
synchronized (Suo.o2) {
System.out.println("o2" + Thread.currentThread().getName());
}
}
}
} else {
while (true) {
synchronized (Suo.o2) {
System.out.println("o2" + Thread.currentThread().getName());
synchronized (Suo.o1) {
System.out.println("o1" + Thread.currentThread().getName());
}
}
}
}
}
}
class Suo {
static Object o1 = new Object();
static Object o2 = new Object();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

运行输出: 
 
上图已经锁死,只要两个线程都启动起来,必定会发生死锁。这个时候赶紧拿jstack练手了 
用jstack命令显示: 

打印内存映射,制作堆Dump命令:Jmap

堆map的概述

堆Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。 一般,在内存不足、GC异常等情况下,我们就会怀疑有内存泄露。这个时候我们就可以制作堆Dump来查看具体情况

用法摘要

Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server) where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-permstat to print permanent generation statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

指定进程号(pid)的进程 jmap [ option ] 指定核心文件 jmap [ option ] 指定远程调试服务器jmap [ option ] [server-id@] 
参数: 
option 选项参数是互斥的(不可同时使用)。想要使用选项参数,直接跟在命令名称后即可。 
pid 需要打印配置信息的进程ID。该进程必须是一个Java进程。想要获取运行的Java进程列表,你可以使用jps。 
executable 产生核心dump的Java可执行文件。 
core 需要打印配置信息的核心文件。 
remote-hostname-or-IP 远程调试服务器的(请查看jsadebugd)主机名或IP地址。 
server-id 可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器。 
选项: 
如果使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。这与Solaris的pmap工具比较相似。 
-dump:[live,]format=b,file= 以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。想要浏览heap dump,你可以使用jhat(Java堆分析工具)读取生成的文件。 
-finalizerinfo 打印等待终结的对象信息。 
-heap 打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和generation wise heap usage。 
-histo[:live] 打印堆的柱状图。其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。 
-permstat 打印Java堆内存的永久保存区域的类加载器的智能统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。 
-F 强制模式。如果指定的pid没有响应,请使用jmap -dump或jmap -histo选项。此模式下,不支持live子选项。 
-h 打印帮助信息。 
-help 打印帮助信息。 
-J 指定传递给运行jmap的JVM的参数。

查看java 堆(heap)使用情况,执行命令:

Jmap –heap pid 

查看堆内存(histogram)中的对象数量及大小。执行命令:

Jmap –histo pid 

总结: 
1. 如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。 
2.要制作堆Dump可以直接使用jvm自带的jmap命令 
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。 
4.使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。 
5.也可以使用 jmap -dump:format=b,file=命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容 
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。

性能监控工具命令:jstat

用法讲解

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
  • 1

参数解释: 
Option — 选项,我们一般使用 -gcutil 查看gc情况 
vmid — VM的进程号,即当前运行的java进程号 
interval– 间隔时间,单位为秒或者毫秒 
count — 打印次数,如果缺省则打印无数次 
参数 interval 和 count 代表查询间隔和次数,如果省略这两个参数,说明只查询一次。

示例: 
Jstat –gc 4100 250 5 

上图中参数的意思:

S0C 年轻代中第一个survivor(幸存区)的容量 (字节) 
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节) 
EC 年轻代中Eden(伊甸园)的容量 (字节) 
EU 年轻代中Eden(伊甸园)目前已使用空间 (字节) 
OU Old代目前已使用空间 (字节) 
PC Perm(持久代)的容量 (字节) 
PU Perm(持久代)目前已使用空间 (字节) 
YGC 从应用程序启动到采样时年轻代中gc次数 
FGC 从应用程序启动到采样时old代(全gc)gc次数 
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s) 
GCT 从应用程序启动到采样时gc用的总时间(s)

Jstat –class 4100 250 5 显示加载class的数量,及所占空间等信息。 

Loaded 装载的类的数量 
Unloaded 卸载类的数量 
Bytes 卸载类的字节数 
Time 装载和卸载类所花费的时间

jstat -compiler 显示VM实时编译的数量等信息 

Compiled 编译任务执行数量 
Invalid 编译任务执行失效数量 
Time 编译任务消耗时间 
FailedType 最后一个编译失败任务的类型 
FailedMethod 最后一个编译失败任务所在的类及方法

Jstat –gccapacity 4100 

NGCMN 年轻代(young)中初始化(最小)的大小(字节) 
NGC 年轻代(young)中当前的容量 (字节) 
S0C 年轻代中第一个survivor(幸存区)的容量 (字节) 
S1C 年轻代中第二个survivor(幸存区)的容量 (字节) 
EC 年轻代中Eden(伊甸园)的容量 (字节) 
OGCMN old代中初始化(最小)的大小 (字节) 
OGCMX old代的最大容量(字节) 
OGC old代当前新生成的容量 (字节) 
OC Old代的容量 (字节) 
PGCMN perm代中初始化(最小)的大小 (字节) 
PGCMX perm代的最大容量 (字节) 
PGC perm代当前新生成的容量 (字节) 
PC Perm(持久代)的容量 (字节) 
YGC 从应用程序启动到采样时年轻代中gc次数 
FGC 从应用程序启动到采样时old代(全gc)gc次数

参考资料

【Java命令学习系列(二)-Jstack】http://www.hollischuang.com/archives/110 
【Java命令学习系列(三)—Jmap】http://www.hollischuang.com/archives/303 
【Java命令学习系列(四)—jstat】http://www.hollischuang.com/archives/481

Java常用命令:jps、jstack、jmap、jstat(带有实例教程)的更多相关文章

  1. Jstack Jmap jstat

    jstack jmap jstat 代码,这里以这个为例怎样使用jstack诊断Java应用程序故障 public class DeadLock { public static void main(S ...

  2. jvm性能监控(3)-jdk自带工具 jps jstack jmap

    一.概要: jps -l 查看现有的java进程 jps -l 显示所有正在运行的java进程id   jstack 查看Java线程      jstack -l pid; 做thread dump ...

  3. java 常用命令工具

    1. jmap (1)分析堆信息 jmap -heap java_pid (2) 导出 java进程 5460 的堆内容 到文件 heap.map ,然后使用 jhat 分析 jmap -dump:l ...

  4. Java常用命令与参数设置

    我介绍的JDK版本: 首先.介绍下JDK常用参数设置,如下是我个人环境的参数: -Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m 我们 ...

  5. JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)

    性能分析工具jstatjmapjhatjstack 前提概要:         JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps.jsta ...

  6. JVM问题诊断常用命令:jinfo,jmap,jstack

    1.jinfo 描述:输出给定 java 进程所有的配置信息.包括 java 系统属性和 jvm 命令行标记等. 用法: jinfo [ option ] pid jinfo [ option ] e ...

  7. Java常用命令

    jps    查看java进程的PID java -XX:+PrintFlagsInitial    显示所有可设置参数及默认值 java -XX:+PrintFlagsFinal    获取到所有可 ...

  8. Java常用命令行工具

    命令基于Sun JDK,用于监控和诊断HotSpot的java 虚拟机. 对应的可执行文件位于$JAVA_HOME/bin/下 jps-虚拟机进程状况工具 选项 作用 -q 只输出LVMID,同进程p ...

  9. java 常用命令

    #查看堆使用情况jmap -heap [pid]#查看占用内存高的对象jmap -histo:live [pid] | head -n 100#查看占用内存高的对象,dump成文件,线下分析jmap ...

随机推荐

  1. Bootstrap select 多选并获取选中的值

    代码: <!DOCTYPE html><html> <head>    <meta charset="UTF-8">    < ...

  2. nginx压力测试和并发预估

    一.Nginx并发预估 预估算法:{(?G)*1024-system}/请求大小 (?G):表示内存大小1024:表示内存容量标准进制system:表示系统和服务占用的额外内存和需要预留的内存请求大小 ...

  3. nginx+keepalived高可用实战

    1.整体架构图如下 2.环境准备 今天所配置的是keepalived+nginx 的负载均衡 下载keepalived软件 [root@LB01 tools]# wget http://www.kee ...

  4. K8S Kubernetes 架构

    Kubernetes最初源于谷歌内部的Borg,提供了面向应用的容器集群部署和管理系统. Kubernetes架构 Kubernetes借鉴了Borg的设计理念,比如Pod.Service.Label ...

  5. 关于hexo与github使用过程中的问题与笔记

    快速阅读 如何用github 和hexo 创建一个blog 1.github中要新建一个与用户名同一样的仓库, 如:homehe.github.io - 必须是io后缀.一个帐户 只能建立一个 2. ...

  6. DB2通过某列分组来去重

    DB2通过某列分组来去重,可防止distinct对大字段的去重报错. row_number() OVER (PARTITION BY COL1 ORDER BY COL2) 表示根据COL1分组,在分 ...

  7. tx1 gpio

  8. session设置存活时间的三种方式

    在web容器中设置(此处以tomcat为例)在tomcat-5.0.28\conf\web.xml中设置,以下是tomcat 5.0中的默认配置: [html] view plain copy < ...

  9. win10 'make' 不是内部或外部命令

    win10 解决“ 'g++' 不是内部或外部命令,也不是可运行的程序或批处理文件”的问题 https://www.jianshu.com/p/9bffbaf12bed windows下提示make不 ...

  10. Phpstudy 无法启动mysql

    原因: 两个mysql版本冲突 本地已经有一个mysql服务(3306)默认开启,再装了phpstudy又会自带一个mysqlla服务(3306) phpstudy启动后会启动mysqlla  发现3 ...