http://www.hollischuang.com/archives/105
JPS
jps位于jdk的bin目录下,其作用是显示当前系统的java进程情况,及其id号。 jps相当于Solaris进程工具ps。不象”pgrep java”或”ps -ef grep java”,jps并不使用应用程序名来查找JVM实例。因此,它查找所有的Java应用程序,包括即使没有使用java执行体的那种(例如,定制的启动器)。另外,jps仅查找当前用户的Java进程,而不是当前系统中的所有进程。
jps –q
jps –m, -m 输出传递给main 方法的参数,在嵌入式jvm上可能是null
Jps –l,输出应用程序main class的完整package名或者应用程序的jar文件完整路径名
Jps –v,输出传递给JVM的参数
JPS失效处理
现象: 用ps -ef|grep java能看到启动的java进程,但是用jps查看却不存在该进程的id。待会儿解释过之后就能知道在该情况下,jconsole、jvisualvm可能无法监控该进程,其他java自带工具也可能无法使用
分析: jps、jconsole、jvisualvm等工具的数据来源就是这个文件(/tmp/hsperfdata_userName/pid)。所以当该文件不存在或是无法读取时就会出现jps无法查看该进程号,jconsole无法监控等问题
原因:
(1)、磁盘读写、目录权限问题 若该用户没有权限写/tmp目录或是磁盘已满,则无法创建/tmp/hsperfdata_userName/pid文件。或该文件已经生成,但用户没有读权限
(2)、临时文件丢失,被删除或是定期清理 对于linux机器,一般都会存在定时任务对临时文件夹进行清理,导致/tmp目录被清空。这也是我第一次碰到该现象的原因。常用的可能定时删除临时目录的工具为crontab、redhat的tmpwatch、ubuntu的tmpreaper等等
这个导致的现象可能会是这样,用jconsole监控进程,发现在某一时段后进程仍然存在,但是却没有监控信息了。
(3)、java进程信息文件存储地址被设置,不在/tmp目录下 上面我们在介绍时说默认会在/tmp/hsperfdata_userName目录保存进程信息,但由于以上1、2所述原因,可能导致该文件无法生成或是丢失,所以java启动时提供了参数(-Djava.io.tmpdir),可以对这个文件的位置进行设置,而jps、jconsole都只会从/tmp目录读取,而无法从设置后的目录读物信息,这是我第二次碰到该现象的原因
Jstack
jstack是java虚拟机自带的一种堆栈跟踪工具
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
NEW,未启动的。不会出现在Dump中。
RUNNABLE,在虚拟机内执行的。
BLOCKED,受阻塞并等待监视器锁。
WATING,无限期等待另一个线程执行特定操作。
TIMED_WATING,有时限的等待另一个线程的特定操作。
TERMINATED,已退出的。
虚拟机执行Full GC时,会阻塞所有的用户线程。因此,即时获取到同步锁的线程也有可能被阻塞。 在查看线程Dump时,首先查看内存使用情况。
Jmap
jmap -dump:live,format=b,file=heapLive.bin pid
jmap是JDK自带的工具软件,主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。可以使用jmap生成Heap Dump。
堆Dump是反应Java堆使用情况的内存镜像,其中主要包括系统信息、虚拟机属性、完整的线程Dump、所有类和对象的状态等。 一般,在内存不足、GC异常等情况下,我们就会怀疑有内存泄露。这个时候我们就可以制作堆Dump来查看具体情况。分析原因。
option 选项参数是互斥的(不可同时使用)。想要使用选项参数,直接跟在命令名称后即可。
<no option>
如果使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。这与Solaris的pmap工具比较相似。-dump:[live,]format=b,file=<filename>
以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<flag>
指定传递给运行jmap的JVM的参数。
pid 需要打印配置信息的进程ID。该进程必须是一个Java进程。想要获取运行的Java进程列表,你可以使用jps。
executable 产生核心dump的Java可执行文件。
core 需要打印配置信息的核心文件。
remote-hostname-or-IP 远程调试服务器的(请查看jsadebugd)主机名或IP地址。
server-id 可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器。
查看java 堆(heap)使用情况,
查看堆内存(histogram)中的对象数量及大小
jmap -histo:live 这个命令执行,JVM会先触发gc,然后再统计信息。
将内存使用的详细情况输出到文件,: jmap
-dump:format=b,file=heapDump 6900
然后用jhat命令可以参看 jhat -port 5000
heapDump
在浏览器中访问:http://localhost:5000/ 查看详细信息
这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap
命令查看堆的使用情况,看一下各个堆空间的占用情况。
4.使用jmap -histo:[live]
查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap
命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容
-dump:format=b,file=<fileName>
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。
jstat
jstat(JVM Statistics Monitoring Tool)是用于监控虚拟机各种运行状态信息的命令行工具。他可以显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形的服务器上,它是运行期定位虚拟机性能问题的首选工具。
jstat位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。可见,Jstat是轻量级的、专门针对JVM的工具,非常适用。
参数解释:
Option — 选项,我们一般使用
-gcutil 查看gc情况
vmid — VM的进程号,即当前运行的java进程号
interval– 间隔时间,单位为秒或者毫秒
count — 打印次数,如果缺省则打印无数次
参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假设需要每250毫秒查询一次进程5828垃圾收集状况,一共查询5次,那命令行如下:
jstat -gc pid 5000
jstat -gcutil 9239 3s 10
对于命令格式中的VMID
与LVMID
需要特别说明下:如果是本地虚拟机进程,VMID
(Virtual Machine IDentifier,虚机标识符)和LVMID
(Local Virtual Machine IDentifier,虚机标识符)是一致的,如果是远程虚拟机进程,那VMID的格式应当是:[protocol:][//] lvmid [@hostname[:port]/servername]
ption
选项option代表这用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集和运行期编译状况,具体选项及作用如下:
–class
监视类装载、卸载数量、总空间及类装载所耗费的时间
–gc
监视Java堆状况,包括Eden区、2个Survivor区、老年代、永久代等的容量
–gccapacity
监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大和最小空间
–gcutil
监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
–gccause
与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
–gcnew
监视新生代GC的状况
–gcnewcapacity
监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间
–gcold
监视老年代GC的状况
–gcoldcapacity
监视内容与——gcold基本相同,输出主要关注使用到的最大和最小空间
–gcpermcapacity
输出永久代使用到的最大和最小空间
–compiler
输出JIT编译器编译过的方法、耗时等信息
–printcompilation
输出已经被JIT编译的方法
jstat –class<pid> :
显示加载class的数量,及所占空间等信息。
Loaded
装载的类的数量Bytes
装载类所占用的字节数Unloaded
卸载类的数量Bytes
卸载类的字节数Time
装载和卸载类所花费的时间
jstat -compiler <pid>
显示VM实时编译的数量等信息。
Compiled
编译任务执行数量Failed
编译任务执行失败数量Invalid
编译任务执行失效数量Time
编译任务消耗时间FailedType
最后一个编译失败任务的类型FailedMethod
最后一个编译失败任务所在的类及方法
jstat -gc <pid>
: 可以显示gc的信息,查看gc的次数,及时间。
S0C
年轻代中第一个survivor(幸存区)的容量 (字节)S1C
年轻代中第二个survivor(幸存区)的容量 (字节)S0U
年轻代中第一个survivor(幸存区)目前已使用空间 (字节)S1U
年轻代中第二个survivor(幸存区)目前已使用空间 (字节)EC
年轻代中Eden(伊甸园)的容量 (字节)EU
年轻代中Eden(伊甸园)目前已使用空间 (字节)OC
Old代的容量 (字节)OU
Old代目前已使用空间 (字节)PC
Perm(持久代)的容量 (字节)PU
Perm(持久代)目前已使用空间 (字节)YGC
从应用程序启动到采样时年轻代中gc次数YGCT
从应用程序启动到采样时年轻代中gc所用时间(s)FGC
从应用程序启动到采样时old代(全gc)gc次数FGCT
从应用程序启动到采样时old代(全gc)gc所用时间(s)GCT
从应用程序启动到采样时gc用的总时间(s)
jstat -gccapacity <pid>:
可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小
NGCMN
年轻代(young)中初始化(最小)的大小(字节)NGCMX
年轻代(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次数
jstat -gcutil <pid>
:统计gc信息
S0
年轻代中第一个survivor(幸存区)已使用的占当前容量百分比S1
年轻代中第二个survivor(幸存区)已使用的占当前容量百分比E
年轻代中Eden(伊甸园)已使用的占当前容量百分比O
old代已使用的占当前容量百分比P
perm代已使用的占当前容量百分比YGC
从应用程序启动到采样时年轻代中gc次数YGCT
从应用程序启动到采样时年轻代中gc所用时间(s)FGC
从应用程序启动到采样时old代(全gc)gc次数FGCT
从应用程序启动到采样时old代(全gc)gc所用时间(s)GCT
从应用程序启动到采样时gc用的总时间(s)
jstat -gcnew <pid>
:年轻代对象的信息。
S0C
年轻代中第一个survivor(幸存区)的容量 (字节)S1C
年轻代中第二个survivor(幸存区)的容量 (字节)S0U
年轻代中第一个survivor(幸存区)目前已使用空间 (字节)S1U
年轻代中第二个survivor(幸存区)目前已使用空间 (字节)TT
持有次数限制MTT
最大持有次数限制EC
年轻代中Eden(伊甸园)的容量 (字节)EU
年轻代中Eden(伊甸园)目前已使用空间 (字节)YGC
从应用程序启动到采样时年轻代中gc次数YGCT
从应用程序启动到采样时年轻代中gc所用时间(s)
jstat -gcnewcapacity<pid>
: 年轻代对象的信息及其占用量。
NGCMN
年轻代(young)中初始化(最小)的大小(字节)NGCMX
年轻代(young)的最大容量 (字节)NGC
年轻代(young)中当前的容量 (字节)S0CMX
年轻代中第一个survivor(幸存区)的最大容量 (字节)S0C
年轻代中第一个survivor(幸存区)的容量 (字节)S1CMX
年轻代中第二个survivor(幸存区)的最大容量 (字节)S1C
年轻代中第二个survivor(幸存区)的容量 (字节)ECMX
年轻代中Eden(伊甸园)的最大容量 (字节)EC
年轻代中Eden(伊甸园)的容量 (字节)YGC
从应用程序启动到采样时年轻代中gc次数FGC
从应用程序启动到采样时old代(全gc)gc次数
jstat -gcold
<pid>:old代对象的信息。
PC Perm(持久代)的容量 (字节)
PU Perm(持久代)目前已使用空间 (字节)
OC Old代的容量 (字节)
OU Old代目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
jstat -gcnewcapacity<pid>
: 年轻代对象的信息及其占用量。
NGCMN
年轻代(young)中初始化(最小)的大小(字节)NGCMX
年轻代(young)的最大容量 (字节)NGC
年轻代(young)中当前的容量 (字节)S0CMX
年轻代中第一个survivor(幸存区)的最大容量 (字节)S0C
年轻代中第一个survivor(幸存区)的容量 (字节)S1CMX
年轻代中第二个survivor(幸存区)的最大容量 (字节)S1C
年轻代中第二个survivor(幸存区)的容量 (字节)ECMX
年轻代中Eden(伊甸园)的最大容量 (字节)EC
年轻代中Eden(伊甸园)的容量 (字节)YGC
从应用程序启动到采样时年轻代中gc次数FGC
从应用程序启动到采样时old代(全gc)gc次数
jstat -gcold
<pid>:old代对象的信息。
PC Perm(持久代)的容量 (字节)
PU Perm(持久代)目前已使用空间 (字节)
OC Old代的容量 (字节)
OU Old代目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
jstat
-gcoldcapacity <pid>: old代对象的信息及其占用量。
OGCMN old代中初始化(最小)的大小 (字节)
OGCMX old代的最大容量(字节)
OGC old代当前新生成的容量 (字节)
OC Old代的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
jstat
-gcpermcapacity<pid>: perm对象的信息及其占用量。
PGCMN perm代中初始化(最小)的大小 (字节)
PGCMX perm代的最大容量 (字节)
PGC perm代当前新生成的容量 (字节)
PC Perm(持久代)的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)
jstat
-printcompilation <pid>:当前VM执行的信息。
Compiled 编译任务的数目
Size 方法生成的字节码的大小
Type 编译类型
Method 类名和方法名用来标识编译的方法。类名使用/做为一个命名空间分隔符。方法名是给定类中的方法。上述格式是由-XX:+PrintComplation选项进行设置的
jhat
jhat(Java Heap Analysis Tool),是一个用来分析java的堆情况的命令。之前的文章讲到过,使用jmap可以生成Java堆的Dump文件。生成dump文件之后就可以用jhat命令,将dump文件转成html的形式,然后通过http访问可以查看堆情况。
jhat命令解析会Java堆dump并启动一个web服务器,然后就可以在浏览器中查看堆的dump文件了。
除了使用jmap命令,还可以通过以下方式:
1、使用 jconsole 选项通过
HotSpotDiagnosticMXBean 从运行时获得堆转储(生成dump文件)、
2、虚拟机启动时如果指定了 -XX:+HeapDumpOnOutOfMemoryError 选项, 则在抛出 OutOfMemoryError 时, 会自动执行堆转储。
3、使用 hprof 命令
使用jhat命令,就启动了一个http服务,端口默认是7000
图片参考前面jmap命令中
在浏览器里面看到dump文件之后就可以进行分析了。这个页面会列出当前进程中的所有对像情况。
一般查看堆异常情况主要看这个两个部分:
Show instance
counts for all classes (excluding platform),平台外的所有对象信息。如下图:
Show heap histogram 以树状图形式展示堆情况。如下图:
具体排查时需要结合代码,观察是否大量应该被回收的对象在一直被引用或者是否有占用内存特别大的对象无法被回收。
用法摘要
这一部分放在后面介绍的原因是一般不太使用。
HollisMacBook-Air:~ hollis$ jhat -help
Usage: jhat [-stack <bool>][-refs <bool>][-port <port>][-baseline <file>][-debug <int>][-version][-h|-help]<file>
-J<flag> Pass<flag> directly to the runtime system.For
example,-J-mx512m to use a maximum heap size of 512MB
-stack false: Turn off tracking object allocation call stack.
-refs false: Turn off tracking of references to objects
-port <port>: Set the port for the HTTP server. Defaults to 7000
-exclude <file>: Specify a file that lists data members that should
be excluded from the reachableFrom query.
-baseline <file>:Specify a baseline objectdump. Objectsin
both heap dumps with the same ID and same class will
be marked asnot being "new".
-debug <int>: Set debug level.
0: No debug output
1: Debug hprof file parsing
2: Debug hprof file parsing,no server
-version Report version number
-h|-help Printthis help andexit
<file> The file to read
-stack false|true
关闭对象分配调用栈跟踪(tracking object allocation call stack)。如果分配位置信息在堆转储中不可用. 则必须将此标志设置为 false. 默认值为 true.
-refs false|true
关闭对象引用跟踪(tracking of references to objects)。默认值为 true. 默认情况下, 返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references), 会统计/计算堆中的所有对象。
-port port-number
设置 jhat HTTP server 的端口号. 默认值 7000.
-exclude exclude-file
指定对象查询时需要排除的数据成员列表文件(a file that lists data members that should be excluded from the reachable objects query)。例如, 如果文件列列出了 java.lang.String.value , 那么当从某个特定对象 Object o 计算可达的对象列表时, 引用路径涉及 java.lang.String.value 的都会被排除。
-baseline exclude-file
指定一个基准堆转储(baseline heap dump)。在两个 heap dumps 中有相同 object ID 的对象会被标记为不是新的(marked as not being new). 其他对象被标记为新的(new). 在比较两个不同的堆转储时很有用.
-debug int
设置 debug 级别. 0 表示不输出调试信息。值越大则表示输出更详细的 debug 信息.
-version
启动后只显示版本信息就退出
-J< flag >
因为 jhat 命令实际上会启动一个JVM来执行, 通过 -J 可以在启动JVM时传入一些启动参数. 例如, -J-Xmx512m 则指定运行 jhat 的Java虚拟机使用的最大堆内存为 512 MB. 如果需要使用多个JVM启动参数,则传入多个 -Jxxxxxx.
OQL
jhat还提供了一种对象查询语言(Object Query Language),OQL有点类似SQL,可以用来查询。
OQL语句的执行页面: http://localhost:7000/oql/
OQL帮助信息页面为: http://localhost:7000/oqlhelp/
OQL的预发可以在帮助页面查看,这里就不详细讲解了。
jinfo
jinfo可以输出java进程、core文件或远程debug服务器的配置信息。这些配置信息包括JAVA系统参数及命令行参数,如果进程运行在64位虚拟机上,需要指明-J-d64
参数,如:jinfo -J-d64 -sysprops pid
另外,Java7的官方文档指出,这一命令在后续的版本中可能不再使用。笔者使用的版本(jdk8)中已经不支持该命令(笔者翻阅了java8中该命令的文档,其中已经明确说明不再支持)。
由于打印jvm常用信息可以使用Jps命令,并且在后续的java版本中可能不再支持,所以这个命令笔者就不详细介绍了。下面给出help信息,读者可自行阅读使用。
javap
javap是jdk自带的一个工具,可以对代码反编译,也可以查看java编译器生成的字节码。
javap命令分解一个class文件,它根据options来决定到底输出什么。如果没有使用options,那么javap将会输出包,类里的protected和public域以及类里的所有方法。javap
将会把它们输出在标准输出上。
用法摘要
-help 帮助
-l 输出行和变量的表
-public 只输出public方法和域
-protected 只输出public和protected类和成员
-package 只输出包,public和protected类和成员,这是默认的
-p -private 输出所有类和成员
-s 输出内部类型签名
-c 输出分解后的代码,例如,类中每一个方法内,包含java字节码的指令,
-verbose 输出栈大小,方法参数的个数
-constants 输出静态final常量
总结
javap可以用于反编译和查看编译器编译后的字节码。平时一般用javap -c
比较多,该命令用于列出每个方法所执行的JVM指令,并显示每个方法的字节码的实际作用。可以通过字节码和源代码的对比,深入分析java的编译原理,了解和解决各种Java原理级别的问题。