jdk命令行工具系列——检视阅读

jdk命令行工具系列——检视阅读

参考

java虚拟机系列

RednaxelaFX知乎问答

RednaxelaFX博客

jps——虚拟机进程状态工具

jps :(JVM Process Status Tool):虚拟机进程状态工具,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)的名称,以及这些进程的本地虚拟机的唯一ID(LVMID,Local Vitual Machine Identifier),它是使用频率最高的JDK命令行工具,因为其他JDK工具大多需要输入它查询到的LVMID来确定要监控的是哪一个虚拟机进程。

对于本地虚拟机进程来说,LVMID与操作系统进程ID(PID,Process Identifier)是一致的。

如果同时启动了多个虚拟机进程,无法根据进程名称定位时,那就只能依靠jps命令显示主类的功能才能区分了。

jps命令格式:

jps options

jps执行样例

D:>jps -l
18292
42132 sun.tools.jps.Jps
22616 com.jvm.test6.Test
32284 org.jetbrains.idea.maven.server.RemoteMavenServer
41228 org.jetbrains.jps.cmdline.Launcher

jps工具主要选项

选项 作用
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给main()函数的参数
-l 输出主类的全名,如果进程执行的是jar包,输出jar路径
-v 输出虚拟机进程启动时JVM参数

jps -q

只输出LVMID,省略主类的名称

D:>jps -q
18292
41012
22616
32284
41228

jps -m

输出虚拟机进程启动时传递给main()函数的参数

D:>jps -m
22616 Test 1 2

jps -l

输出主类的全名,如果进程执行的是jar包,输出jar路径。

D:>jps -l
22616 com.jvm.test6.Test

jar包的情况

[root@localhost ~]# jps -l
43248 ./code/p-parent/p-other/p-api/target/p-api-0.0.1-SNAPSHOT.jar
43249 ./code/p-parent/p-job/target/p-job-0.0.1-SNAPSHOT.jar
52786 sun.tools.jps.Jps
43250 ./code/p-parent/p-core/p-core-admin/target/p-core-admin-0.0.1-SNAPSHOT.jar
43240 ./code/p-parent/p-cloud/p-cloud-discovery/target/p-cloud-discovery-0.0.1-SNAPSHOT.jar
43241 ./code/p-parent/p-msg/broker/p-msg-service/target/p-msg-service-0.0.1-SNAPSHOT.jar
43242 ./code/p-parent/p-dts/service/p-dts-service/target/p-dts-service-0.0.1-SNAPSHOT.jar
43243 ./code/p-parent/p-notification/p-notification-service/target/p-notification-service-0.0.1-SNAPSHOT.jar
43244 ./code/p-parent/p-account/p-account-service/target/p-account-service-0.0.1-SNAPSHOT.jar
43245 ./code/p-parent/p-borrow/p-borrow-service/target/p-borrow-service-0.0.1-SNAPSHOT.jar
43246 ./code/p-parent/p-depository/p-depository-service/target/p-depository-service-0.0.1-SNAPSHOT.jar
43247 ./code/p-parent/p-invest/p-invest-service/target/p-invest-service-0.0.1-SNAPSHOT.jar

jps -v

输出虚拟机进程启动时JVM参数

D:>jps -v
22616 Test -Xms10m -Xmx1000m

jstat——虚拟机统计信息监控工具

jstat(JVM Statistics Monitorning Tool)

用于监控虚拟机各种运行状态信息的命令行工具。

它可以显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,它是运行期定位虚拟机性能问题的首选工具。

语法:

[root@localhost ~]# jstat -help
Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
  <option>      An option reported by the -options option
  <vmid>        Virtual Machine Identifier. A vmid takes the following form:
                     <lvmid>[@<hostname>[:<port>]]
                Where <lvmid> is the local vm identifier for the target
                Java virtual machine, typically a process id; <hostname> is
                the name of the host running the target Java virtual machine;
                and <port> is the port number for the rmiregistry on the
                target host. See the jvmstat documentation for a more complete
                description of the Virtual Machine Identifier.
  <lines>       Number of samples between header lines.
  <interval>    Sampling interval. The following forms are allowed:
                    <n>["ms"|"s"]
                Where <n> is an integer and the suffix specifies the units as 
                milliseconds("ms") or seconds("s"). The default units are "ms".
  <count>       Number of samples to take before terminating.
  -J<flag>      Pass <flag> directly to the runtime system.

参数 interval 和 count 代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假如需要每250毫秒查询一次进程2764垃圾收集的情况,一共查询20次,那么命令应该是:jstat -gc 2764 250 20

//示例:查看本地idea的gc情况
//获得idea进程LVMID
jps -v / jps -l
//每3秒打印一次gc情况打印20次
F:>jstat -gc 9884 3000 20
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
24320.0 24320.0 1548.3  0.0   194752.0 160077.1  486592.0   183242.4  373312.0 348566.7 49336.0 44180.1   1876   15.138  105    39.248   54.386
24320.0 24320.0 1548.3  0.0   194752.0 164783.3  486592.0   183242.4  373312.0 348566.7 49336.0 44180.1   1876   15.138  105    39.248   54.386

主要选项

选项 作用
-class 监视类装载、卸载数量、总空间及类装载所耗费的时间
-gc 监视Java堆状况,包括Eden区、2个Survivor区、老年代、永久代等容量、已用空间、GC合计时间等信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注java堆各区域使用到的最大和最小空间
-gcutil 监控内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC的状况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间
-gcold 监视老年代GC的状况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大和最小空间
-gcpermcapacity 输出永久代使用到的最大和最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已被JIT编译的方法

统计加载类的信息

命令:jstat -class

[root@test1117 ~]# jstat -class 21434
Loaded  Bytes  Unloaded  Bytes     Time   
  8776 18268.0        0     0.0       6.05

列名 说明
Loaded 装载的类的数量
Bytes 装载类所占用的字节数
Unloaded 卸载类的数量
Bytes 卸载类所占用的字节数
Time 装载类和卸载类所耗费的时间(毫秒)

编译统计

命令:jstat -compiler pid

[root@test1117 ~]# jstat -compiler 21434
Compiled Failed Invalid   Time   FailedType FailedMethod
    1721      1       0    34.87          1 org/apache/catalina/loader/WebappClassLoaderBase findResourceInternal

列名 说明
Compiled 编译任务执行数量
Failed 编译任务执行失败的数量
Invalid 编译任务失效的数量
Time 编译总耗时(毫秒)
FailedType 最后一个编译失败任务的类型
FailedMethod 最后一个编译失败任务所在的类及方法

垃圾回收统计——GC的各区域容量和已使用容量、GC次数及消耗时间

命令:jstat -gc

[root@test1117 ~]# jstat -gc 21434
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
13312.0 13824.0  0.0   1040.0 146432.0 140089.9  349696.0   252384.5  262144.0 55374.3     47    0.921   0      0.000    0.921

列名 说明
S0C 年轻代中第一个survior(幸存区)的容量(kb)
S1C 年轻代中第二个survior(幸存区)的容量(kb)
S0U 年轻代中第一个survior(幸存区)目前已使用的容量(kb)
S1U 年轻代中第二个survior(幸存区)目前已使用的容量(kb)
EC eden区的容量(kb):eden capacity
EU eden区目前已使用的容量(kb):eden used
OC 老年代的容量(kb):old capacity
OU 老年代目前已使用的容量(kb)
PC perm永久代的容量(kb)
PU perm永久代目前已使用的容量(kb)
YGC 从应用程序启动到采集时年轻代中gc次数
YGCT 从应用程序启动到采集时年轻代中gc所用总时间(秒)
FGC 从应用程序启动到采集时老年代中gc次数
FGCT 从应用程序启动到采集时老年代gc所用的总时间(秒)
GCT 从应用程序启动到采集时gc所用的总时间(秒)
CCSC 压缩类空间容量(KB) compact class space capacity ,jdk1.8
CCSU 压缩空间目前已使用大小(KB) ,jdk1.8
MC 元空间的容量(KB) Metaspace capacity,jdk1.8的方法区不再是永久代实现,而是元空间
MU 元空间目前已使用大小(KB) ,jdk1.8

统计gc信息——关注各区域已使用空间占总空间的百分比

命令:jstat -gcutil

[root@test1117 ~]# jstat -gcutil 21434
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  7.81   0.00  46.68  72.18  21.12     48    0.934     0    0.000    0.934

列名 说明
S0 年轻代中第一个(survisor)幸存区已使用的容量占比
S1 年轻代中第二个(survisor)幸存区已使用的容量占比
E 伊旬园(eden)区已使用的容量占比
O 老年代区已使用的容量占比
P 永久代(perm)已使用的容量占比
YGC 年轻代到目前gc次数
YGCT 年轻代到目前gc耗费的总时间(秒)
FGC 老年代目前gc次数
FGCT 老年代目前gc耗费的总时间(秒)
GC 从应用程序到目前gc总耗时(秒)
M 元空间(metaspace)已使用的容量占比,jdk1.8后方法区用元空间实现
CCS 压缩类空间已使用的容量占比

堆内存统计——主要关注java堆各区域使用到的最大和最小空间

命令:jstat -gccapacity

[root@test1117 ~]# jstat -gccapacity 21434
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC      PGCMN    PGCMX     PGC       PC     YGC    FGC 
175104.0 393216.0 175104.0 13312.0 12288.0 149504.0   349696.0   655360.0   349696.0   349696.0 262144.0 524288.0 262144.0 262144.0     48     0

列名 说明
NGCMN 年轻代(young)中初始化(最小)的大小(kb)
NGCMX 年轻代(young)中初始化(最大)的大小(kb)
NGC 年轻代(young)中当前的容量(kb)
S0C 年轻代中第一个(survisor)幸存区的容量(kb)
S1C 年轻代中第二个(survisor)幸存区的容量(kb)
EC 年轻代中(Eden)伊旬园的容量(kb)
OGCMN 老年代(old)中初始化(最小)的容量(kb)
OGCMX 老年代(old)中初始化(最大)的容量(kb)
OGC 当前老年代的大小(kb)
OC 当前老年代的大小(kb)
PGCMN 永久代(perm)中初始化(最小)的大小(kb)
PGCMX 永久代(perm)中初始化(最大)的大小(kb)
PGC 永久代当前的大小(kb)
PC 永久代当前的大小(kb)
YGC 从应用程序启动到采集时年轻代gc的次数
FGC 从应用程序启动带采集时老年代gc的次数
MCMN 元空间(metaspace)中初始化(最小)的大小(kb),jdk1.8后方法区用元空间实现
MCMX 元空间(metaspace)中初始化(最大)的大小(kb),jdk1.8
MC 元空间当前的大小(kb),jdk1.8
CCSMN 压缩类空间中初始化(最小)的大小(kb),jdk1.8
CCSMX 压缩类空间中初始化(最大)的大小(kb),jdk1.8
CCSC 压缩类空间当前的大小(kb),jdk1.8

新生代垃圾回收统计——监视新生代GC的状况

命令:jstat -gcnew

D:codeIdeaProjectsjavafx-demo1src	est>jstat -gcnew 4016
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT
1024.0 1024.0    0.0    0.0 15  15  512.0   8192.0   7328.4    465    0.120

列名 说明
S0C 年轻代中第一个(survisor)幸存区的容量(kb)
S1C 年轻代中第二个(survisor)幸存区的容量(kb)
S0U 年轻代中第一个(survisor)幸存区目前已使用的容量(kb)
S1U 年轻代中第二个(survisor)幸存区目前已使用的容量(kb)
TT 对象在新生代中存活的次数
MTT 对象在新生代中存活的最大次数
DSS 当前需要survivor(幸存区)的容量 (kb)(Eden区已满)
EC 伊旬园(eden)区的大小(kb)
EU 伊旬园(eden)区已使用的大小(kb)
YGC 到目前年轻代gc的次数
YGCT 到目前年轻代gc所耗费的时间(秒)

新生代内存统计——主要关注新生代使用到的最大和最小空间

命令:jstat -gcnewcapacity

D:codeIdeaProjectsjavafx-demo1src	est>jstat -gcnewcapacity 4016
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC
   10240.0    10240.0    10240.0   1024.0   1024.0   1024.0   1024.0     8192.0     8192.0   647     0

列名 说明
NGCMN 年轻代中初始化最小容量(kb)
NGCMX 年轻代中初始化最大容量(kb)
NGC 年轻代当前容量(kb)
S0CMX 年轻代第一个幸存区(survisor)最大容量(kb)
S0C 年轻代第一个幸存区(survisor)当前容量(kb)
S1CMX 年轻代第二个幸存区(survisor)最大容量(kb)
S1C 年轻代第二个幸存区(survisor)当前容量(kb)
ECMX 年轻代伊旬园区(Eden)最大容量(kb)
EC 年轻代伊旬园区(Eden)当前容量(kb)
YGC 截止到目前年轻代gc次数
FGC 截止到目前老年代gc次数

老年代垃圾回收统计——监视老年代GC的状况

命令:jstat -gcold

[root@test1117 ~]# jstat -gcold 21434
   PC       PU        OC          OU       YGC    FGC    FGCT     GCT   
262144.0  55374.3    349696.0    252424.5     48     0    0.000    0.934

列名 说明
PC 永久区(perm)容量(kb)
PU 永久区(perm)已使用容量(kb)
OC 老年代容量(kb)
OU 老年代已使用容量(kb)
YGC 截止到目前年轻代gc次数
FGC 截止到目前老年代gc次数
GCT 截止到目前gc耗费的总时间(秒)
MC 元空间容量(kb),jdk1.8后方法区用元空间实现
MU 元空间已使用容量(kb),jdk1.8
CCSC 压缩类空间容量(kb),jdk1.8
CCSU 压缩类空间已使用容量(kb),jdk1.8

老年代内存统计——关注老年代使用到的最大和最小空间

命令:jstat -gcoldcapacity

[root@test1117 ~]# jstat -gcoldcapacity 21434
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT   
   349696.0    655360.0    349696.0    349696.0    48     0    0.000    0.934

列名 说明
OGCMN 老年代最小容量(kb)
OGCMX 老年代最大容量(kb)
OGC 老年代目前生成的容量(kb):表示目前老年代的全部容量(容量或根据需要变化)
OC 老年代目前容量(kb)
YGC 截止到目前年轻代gc次数
FGC 截止到目前老年代gc次数
FGCT 截止到目前老年代gc耗费的总时间(秒)
GCT 截止到目前gc耗费的总时间(秒)

永久代内存统计——永久代使用到的最大和最小空间

命令:jstat -gcpermcapacity

如果是jdk1.8使用 jstat -gcmetacapacity 9884 1000 3

[root@test1117 ~]# jstat -gcpermcapacity 21434 /jstat -gcmetacapacity 9884 1000 3
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT   
  262144.0   524288.0   262144.0   262144.0    49     0    0.000    0.948

列名 说明
PGCMN 永久代最小容量(kb)
PGCMX 永久代最大容量(kb)
PGC 永久代当前生成的容量(kb):perm general capacity :永久代总的容量
PC 永久代当前容量(kb)
YGC 截止目前年轻代gc次数
FGC 截止目前老年代gc次数
FGCT 截止目前年轻代gc耗费的总时间(秒)
GCT 截止目前老年代gc耗费的总时间(秒)

最近二次gc统计——主要关注已使用空间占总空间的百分比 ,会额外输出导致上一次GC产生的原因

命令:gstat -gccause

[root@test1117 ~]# jstat -gccause 21434
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
  0.00   8.72  33.06  72.20  21.12     49    0.948     0    0.000    0.948 Allocation Failure   No GC

列名 说明
LGCC 最近垃圾回收的原因
GCC 当前垃圾回收的原因

JVM编译方法统计

命令:jstat -printcompilation

[root@test1117 ~]# jstat -printcompilation 21434
Compiled  Size  Type Method
    1721    554    1 org/jboss/netty/channel/socket/nio/AbstractNioWorker write0

列名 说明
Compiled 最近编译方法的数量
Size 最近编译方法的字节码数量?单位呢?
Type 最近编译方法的编译类型
Method 方法名标识

疑问:

Q: 如下linux的命令行格式如何理解,尖括号和中括号表示什么意思?

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

Q:老年代(old)中初始化(最小)的容量(kb),这个初始化怎么理解?是不是只一开始分配的空间大小和后面动态扩容空间后的容量大小?

Q:当操作 jstat -gcnew pid 时,对于显示出来的下面这3个值要怎么理解?TT 对象在新生代中存活的次数是指哪部分的对象,是指当前所有存活的对象中,其中存活时间最久的那个对象在新生代中存活的次数么?而对象在新生代中存活的最大次数是指从启动到目前为止历史上对象在对象在新生代中存活的最大次数么?当前需要survivor(幸存区)的容量 (kb)是指什么?是指上一次eden区满时需要的survivor(幸存区)的容量大小是么?

TT 对象在新生代中存活的次数 MTT 对象在新生代中存活的最大次数 DSS 当前需要survivor(幸存区)的容量 (kb)(Eden区已满)

Q: CCSC:压缩类空间是什么意思?

A: 参考

这是java1.8后把方法区的实现从永久代改为元空间实现后有的概念,Java8在UseCompressedOops之外,额外增加了一个新选项叫做UseCompressedClassPointer。这个选项打开后,class信息中的指针也用32bit的Compressed版本。而这些指针指向的空间被称作“Compressed Class Space”。默认大小是1G,但可以通过“CompressedClassSpaceSize”调整。是给元空间使用的。

如果你的java程序引用了太多的包,有可能会造成这个空间不够用,于是会看到

java.lang.OutOfMemoryError: Compressed class space

这时,一般调大CompreseedClassSpaceSize就可以了。

扩展作者回答:

在Java8以前,有一个选项是UseCompressedOops:使用压缩原始指针。所谓OOPS是指“ordinary object pointers“,就是原始指针。Java Runtime可以用这个指针直接访问指针对应的内存,做相应的操作(比如发起GC时做copy and sweep)。

那么Compressed是啥意思?64bit的JVM出现后,OOPS的尺寸也变成了64bit,比之前的大了一倍。这会引入性能损耗——占的内存double了,并且同尺寸的CPU Cache要少存一倍的OOPS。

于是就有了UseCompressedOops这个选项。打开后,OOPS变成了32bit。但32bit的base是8,所以能引用的空间是32GB——这远大于目前经常给jvm进程内存分配的空间。

一般建议不要给JVM太大的内存,因为Heap太大,GC停顿实在是太久了。所以很多开发者喜欢在大内存机器上开多个JVM进程,每个给比如最大8G以下的内存。

从JDK6_u23开始UseCompressedOops被默认打开了。因此既能享受64bit带来的好处,又避免了64bit带来的性能损耗。当然,如果你有机会使用超过32G的堆内存,记得把这个选项关了。

到了Java8,永久代被干掉了,有了“meta space”的概念,存储jvm中的元数据,包括byte code,class等信息。Java8在UseCompressedOops之外,额外增加了一个新选项叫做UseCompressedClassPointer:使用压缩类指针。这个选项打开后,class信息中的指针也用32bit的Compressed版本。而这些指针指向的空间被称作“Compressed Class Space”。默认大小是1G,但可以通过“CompressedClassSpaceSize”调整。

如果你的java程序引用了太多的包,有可能会造成这个空间不够用,于是会看到

java.lang.OutOfMemoryError: Compressed class space

这时,一般调大CompreseedClassSpaceSize就可以了。

-XX:+UseCompressedClassPointers 是需要 -XX:+UseCompressedOops 开启的,所以堆大小要是大于 32G,CompressedOops 自动关闭,CompressedClassPointers 也会关闭的,关闭了就没有 Compressed Class Space 了,这块就是 Class Space 了。

-XX:CompressedClassSpaceSize 大小的设置也是有限制,因为压缩开关是受制于 32G,所以这个自然也是不能大于 32G,不过 hotspot 规定了这个参数不准大于 3G,所以这个参数其实是不能大于 3G。

一般来说,平均一个 Klass 大小可以当成 1K 来算,默认的 1G 大小可以存储 100 万的 Klass。如果遇到了 java.lang.OutOfMemoryError: Compressed class space,就是类太多了,需要结合具体情况去选择 JVM 调优还是 bug 排查。

jinfo——jvm配置信息工具

jinfo(Configuration Info for Java)的作用是实时地查看和调整虚拟机的各项参数。

使用jps -v 可以查看虚拟机启动时显示指定的参数列表,但是如果想知道未被显示指定的参数的系统默认值,可以使用jinfo的-flag选项进行查询了。

[root@localhost ~]# jinfo
Usage:
    jinfo [option] <pid>
        (to connect to running process)
    jinfo [option] <executable <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags
    -sysprops            to print Java system properties
    <no option>          to print both of the above
    -h | -help           to print this help message

jinfo -flags ——打印所有的jvm标志信息

注意打印所有的jvm标志信息要用 -flags

F:
ew>jps -l
6512 org.jetbrains.jps.cmdline.Launcher
13928 sun.tools.jps.Jps
8252 com.intellij.rt.execution.junit.JUnitStarter
9884

F:
ew>jinfo -flags 8252
Attaching to process ID 8252, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=104857600 -XX:MaxNewSize=34603008 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=3145728 -XX:OldSize
=7340032 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xms10m -Xmx100m -Didea.test.cyclic.buffer.size=1048576 -javaagent:F:ideaIntelliJ IDEA 2018.1.6libidea_rt.jar=52421:F:ideaIntelliJ IDEA 2018.1.6in -Dfile.encodi
ng=UTF-8
  • Non-default VM flags: 非默认VM标志
  • Command line: 命令行中指定的jvm参数

jinfo -flag —— 打印指定的jvm参数信息

[root@localhost ~]# jinfo -flag InitialHeapSize 113595
-XX:InitialHeapSize=522190848

jinfo -flag [+|-] ——启用或者禁用指定的jvm参数

我们运行一段程序,下面这段程序vm参数设置为:-Xms5m -Xmx5m,运行过程中会参数OOM,在运行过程中,我们添加vm参数:+HeapDumpOnOutOfMemoryError:发生OOM的时候,让程序打印堆dump文件

public class Test7 {
    private static final int _1M = 1024 * 1024;
    public static void main(String[] args) throws InterruptedException {
        List<Object> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            TimeUnit.SECONDS.sleep(3);
            list.add(new byte[_1M]);
        }
    }
}

运行过程中添加参数

C:UsersThink>jps -l
44520 com.jvm.test7.Test7

C:UsersThink>jinfo -flag +HeapDumpOnOutOfMemoryError 44520

C:UsersThink>jinfo -flags 44520
Attaching to process ID 44520, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Non-default VM flags: -XX:CICompilerCount=4 -XX:+HeapDumpOnOutOfMemoryError -XX:InitialHeapSize=6291456 -XX:MaxHeapSize=6291456 -XX:MaxNewSize=2097152 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=2097152 -XX:OldSize=4194304 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53193,suspend=y,server=n -Xms5m -Xmx5m -Dfile.encoding=UTF-8

程序运行结果:

Connected to the target VM, address: '127.0.0.1:53193', transport: 'socket'
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid44520.hprof ...
Disconnected from the target VM, address: '127.0.0.1:53193', transport: 'socket'
Heap dump file created [4535342 bytes in 0.009 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.jvm.test7.Test7.main(Test7.java:18)

jinfo -flag = ——给指定的jvm参数设置值

注意很多堆等内存大小值是不能设置的,dump内存可以设置。

jinfo -flag HeapDumpPath=/temooo/heap.hprof 9580

jinfo -sysprops ——打印系统参数信息

打印的信息和System.getProperties()一样。

C:UsersThink>jinfo -sysprops 44748
Attaching to process ID 44748, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.121-b13
sun.boot.library.path = D:installsoftJavajdk1.8.0_121jrein
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level =
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
user.dir = D:codeIdeaProjectsspring-aop-demo
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_121-b13
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = D:installsoftJavajdk1.8.0_121jrelibendorsed
line.separator =

java.io.tmpdir = C:UsersThinkAppDataLocalTemp
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = D:installsoftJavajdk1.8.0_121in;C:WindowsSunJavain;C:Windowssystem32;C:Windows;C:ProgramDataDockerDesktopversion-bin;C:Program FilesDockerDockerResourcesin;D:installsoftmavenapache-maven-3.3.9in;D:installsoftJavajdk1.8.0_121in;D:installsoftJavajdk1.8.0_121jrein;C:ProgramDataOracleJavajavapath;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsiCLS;C:Program FilesIntelIntel(R) Management Engine ComponentsiCLS;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:WindowsSystem32OpenSSH;C:Program FilesIntelWiFiin;C:Program FilesCommon FilesIntelWirelessCommon;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsDAL;C:Program FilesIntelIntel(R) Management Engine ComponentsDAL;D:installsoftTortoiseSVNin;C:Program Files (x86)Common FilesThunder NetworkKanKanCodecs;D:adyffmpegffmpegin;D:installsoftMySQLmysql-5.7.25-winx64in;D:installsoftGitcmd;D:installsoftGoin;C:UsersThinkAppDataLocalMicrosoftWindowsApps;;D:installsoftSSH Communications SecuritySSH Secure Shell;D:installsoftDocker Toolbox;D:installsoftDocker Toolbox;C:UsersThinkgoin;.
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.0
user.home = C:UsersThink
user.timezone =
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = Think
java.class.path = D:installsoftJavajdk1.8.0_121jrelibcharsets.jar;D:installsoftJavajdk1.8.0_121jrelibdeploy.jar;D:installsoftJavajdk1.8.0_121jrelibextaccess-bridge-64.jar;D:installsoftJavajdk1.8.0_121jrelibextcldrdata.jar;D:installsoftJavajdk1.8.0_121jrelibextdnsns.jar;D:installsoftJavajdk1.8.0_121jrelibextjaccess.jar;D:installsoftJavajdk1.8.0_121jrelibextjfxrt.jar;D:installsoftJavajdk1.8.0_121jrelibextlocaledata.jar;D:installsoftJavajdk1.8.0_121jrelibext
ashorn.jar;D:installsoftJavajdk1.8.0_121jrelibextsunec.jar;D:installsoftJavajdk1.8.0_121jrelibextsunjce_provider.jar;D:installsoftJavajdk1.8.0_121jrelibextsunmscapi.jar;D:installsoftJavajdk1.8.0_121jrelibextsunpkcs11.jar;D:installsoftJavajdk1.8.0_121jrelibextzipfs.jar;D:installsoftJavajdk1.8.0_121jrelibjavaws.jar;D:installsoftJavajdk1.8.0_121jrelibjce.jar;D:installsoftJavajdk1.8.0_121jrelibjfr.jar;D:installsoftJavajdk1.8.0_121jrelibjfxswt.jar;D:installsoftJavajdk1.8.0_121jrelibjsse.jar;D:installsoftJavajdk1.8.0_121jrelibmanagement-agent.jar;D:installsoftJavajdk1.8.0_121jrelibplugin.jar;D:installsoftJavajdk1.8.0_121jrelib
esources.jar;D:installsoftJavajdk1.8.0_121jrelib
t.jar;D:codeIdeaProjectsspring-aop-demo	arget	est-classes;D:codeIdeaProjectsspring-aop-demo	argetclasses;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-aop2.1.4.RELEASEspring-boot-starter-aop-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter2.1.4.RELEASEspring-boot-starter-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot2.1.4.RELEASEspring-boot-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-context5.1.6.RELEASEspring-context-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-expression5.1.6.RELEASEspring-expression-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-autoconfigure2.1.4.RELEASEspring-boot-autoconfigure-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-logging2.1.4.RELEASEspring-boot-starter-logging-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0chqoslogbacklogback-classic1.2.3logback-classic-1.2.3.jar;D:installsoftmaven.m2
epository3.3.9_0chqoslogbacklogback-core1.2.3logback-core-1.2.3.jar;D:installsoftmaven.m2
epository3.3.9_0orgslf4jslf4j-api1.7.26slf4j-api-1.7.26.jar;D:installsoftmaven.m2
epository3.3.9_0orgapachelogginglog4jlog4j-to-slf4j2.11.2log4j-to-slf4j-2.11.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgapachelogginglog4jlog4j-api2.11.2log4j-api-2.11.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgslf4jjul-to-slf4j1.7.26jul-to-slf4j-1.7.26.jar;D:installsoftmaven.m2
epository3.3.9_0javaxannotationjavax.annotation-api1.3.2javax.annotation-api-1.3.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgyamlsnakeyaml1.23snakeyaml-1.23.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-aop5.1.6.RELEASEspring-aop-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-beans5.1.6.RELEASEspring-beans-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgaspectjaspectjweaver1.9.2aspectjweaver-1.9.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgprojectlomboklombok1.18.6lombok-1.18.6.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-test2.1.4.RELEASEspring-boot-starter-test-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-test2.1.4.RELEASEspring-boot-test-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-test-autoconfigure2.1.4.RELEASEspring-boot-test-autoconfigure-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0comjaywayjsonpathjson-path2.4.0json-path-2.4.0.jar;D:installsoftmaven.m2
epository3.3.9_0junitjunit4.12junit-4.12.jar;D:installsoftmaven.m2
epository3.3.9_0orgassertjassertj-core3.11.1assertj-core-3.11.1.jar;D:installsoftmaven.m2
epository3.3.9_0orgmockitomockito-core2.23.4mockito-core-2.23.4.jar;D:installsoftmaven.m2
epository3.3.9_0
etytebuddyyte-buddy1.9.12yte-buddy-1.9.12.jar;D:installsoftmaven.m2
epository3.3.9_0
etytebuddyyte-buddy-agent1.9.12yte-buddy-agent-1.9.12.jar;D:installsoftmaven.m2
epository3.3.9_0orgobjenesisobjenesis2.6objenesis-2.6.jar;D:installsoftmaven.m2
epository3.3.9_0orghamcresthamcrest-core1.3hamcrest-core-1.3.jar;D:installsoftmaven.m2
epository3.3.9_0orghamcresthamcrest-library1.3hamcrest-library-1.3.jar;D:installsoftmaven.m2
epository3.3.9_0orgskyscreamerjsonassert1.5.0jsonassert-1.5.0.jar;D:installsoftmaven.m2
epository3.3.9_0comvaadinexternalgoogleandroid-json.0.20131108.vaadin1android-json-0.0.20131108.vaadin1.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-core5.1.6.RELEASEspring-core-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-jcl5.1.6.RELEASEspring-jcl-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-test5.1.6.RELEASEspring-test-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgxmlunitxmlunit-core2.6.2xmlunit-core-2.6.2.jar;D:installsoftJavajdk1.8.0_121lib	ools.jar;E:yjd软 件Intellij IDEAideaIU-2017.1.5.winlibidea_rt.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.jvm.test6.Test 1 2
java.home = D:installsoftJavajdk1.8.0_121jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_121
java.ext.dirs = D:installsoftJavajdk1.8.0_121jrelibext;C:WindowsSunJavalibext
sun.boot.class.path = D:installsoftJavajdk1.8.0_121jrelib
esources.jar;D:installsoftJavajdk1.8.0_121jrelib
t.jar;D:installsoftJavajdk1.8.0_121jrelibsunrsasign.jar;D:installsoftJavajdk1.8.0_121jrelibjsse.jar;D:installsoftJavajdk1.8.0_121jrelibjce.jar;D:installsoftJavajdk1.8.0_121jrelibcharsets.jar;D:installsoftJavajdk1.8.0_121jrelibjfr.jar;D:installsoftJavajdk1.8.0_121jreclasses
java.vendor = Oracle Corporation
file.separator = 
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64

jinfo ——打印以上所有配置信息

C:UsersThink>jinfo 44748
Attaching to process ID 44748, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.121-b13
sun.boot.library.path = D:installsoftJavajdk1.8.0_121jrein
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = ;
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level =
sun.java.launcher = SUN_STANDARD
user.script =
user.country = CN
user.dir = D:codeIdeaProjectsspring-aop-demo
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_121-b13
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = D:installsoftJavajdk1.8.0_121jrelibendorsed
line.separator =

java.io.tmpdir = C:UsersThinkAppDataLocalTemp
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = D:installsoftJavajdk1.8.0_121in;C:WindowsSunJavain;C:Windowssystem32;C:Windows;C:ProgramDataDockerDesktopversion-bin;C:Program FilesDockerDockerResourcesin;D:installsoftmavenapache-maven-3.3.9in;D:installsoftJavajdk1.8.0_121in;D:installsoftJavajdk1.8.0_121jrein;C:ProgramDataOracleJavajavapath;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsiCLS;C:Program FilesIntelIntel(R) Management Engine ComponentsiCLS;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;C:WindowsSystem32OpenSSH;C:Program FilesIntelWiFiin;C:Program FilesCommon FilesIntelWirelessCommon;C:Program Files (x86)IntelIntel(R) Management Engine ComponentsDAL;C:Program FilesIntelIntel(R) Management Engine ComponentsDAL;D:installsoftTortoiseSVNin;C:Program Files (x86)Common FilesThunder NetworkKanKanCodecs;D:adyffmpegffmpegin;D:installsoftMySQLmysql-5.7.25-winx64in;D:installsoftGitcmd;D:installsoftGoin;C:UsersThinkAppDataLocalMicrosoftWindowsApps;;D:installsoftSSH Communications SecuritySSH Secure Shell;D:installsoftDocker Toolbox;D:installsoftDocker Toolbox;C:UsersThinkgoin;.
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.0
user.home = C:UsersThink
user.timezone =
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = Think
java.class.path = D:installsoftJavajdk1.8.0_121jrelibcharsets.jar;D:installsoftJavajdk1.8.0_121jrelibdeploy.jar;D:installsoftJavajdk1.8.0_121jrelibextaccess-bridge-64.jar;D:installsoftJavajdk1.8.0_121jrelibextcldrdata.jar;D:installsoftJavajdk1.8.0_121jrelibextdnsns.jar;D:installsoftJavajdk1.8.0_121jrelibextjaccess.jar;D:installsoftJavajdk1.8.0_121jrelibextjfxrt.jar;D:installsoftJavajdk1.8.0_121jrelibextlocaledata.jar;D:installsoftJavajdk1.8.0_121jrelibext
ashorn.jar;D:installsoftJavajdk1.8.0_121jrelibextsunec.jar;D:installsoftJavajdk1.8.0_121jrelibextsunjce_provider.jar;D:installsoftJavajdk1.8.0_121jrelibextsunmscapi.jar;D:installsoftJavajdk1.8.0_121jrelibextsunpkcs11.jar;D:installsoftJavajdk1.8.0_121jrelibextzipfs.jar;D:installsoftJavajdk1.8.0_121jrelibjavaws.jar;D:installsoftJavajdk1.8.0_121jrelibjce.jar;D:installsoftJavajdk1.8.0_121jrelibjfr.jar;D:installsoftJavajdk1.8.0_121jrelibjfxswt.jar;D:installsoftJavajdk1.8.0_121jrelibjsse.jar;D:installsoftJavajdk1.8.0_121jrelibmanagement-agent.jar;D:installsoftJavajdk1.8.0_121jrelibplugin.jar;D:installsoftJavajdk1.8.0_121jrelib
esources.jar;D:installsoftJavajdk1.8.0_121jrelib
t.jar;D:codeIdeaProjectsspring-aop-demo	arget	est-classes;D:codeIdeaProjectsspring-aop-demo	argetclasses;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-aop2.1.4.RELEASEspring-boot-starter-aop-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter2.1.4.RELEASEspring-boot-starter-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot2.1.4.RELEASEspring-boot-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-context5.1.6.RELEASEspring-context-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-expression5.1.6.RELEASEspring-expression-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-autoconfigure2.1.4.RELEASEspring-boot-autoconfigure-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-logging2.1.4.RELEASEspring-boot-starter-logging-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0chqoslogbacklogback-classic1.2.3logback-classic-1.2.3.jar;D:installsoftmaven.m2
epository3.3.9_0chqoslogbacklogback-core1.2.3logback-core-1.2.3.jar;D:installsoftmaven.m2
epository3.3.9_0orgslf4jslf4j-api1.7.26slf4j-api-1.7.26.jar;D:installsoftmaven.m2
epository3.3.9_0orgapachelogginglog4jlog4j-to-slf4j2.11.2log4j-to-slf4j-2.11.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgapachelogginglog4jlog4j-api2.11.2log4j-api-2.11.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgslf4jjul-to-slf4j1.7.26jul-to-slf4j-1.7.26.jar;D:installsoftmaven.m2
epository3.3.9_0javaxannotationjavax.annotation-api1.3.2javax.annotation-api-1.3.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgyamlsnakeyaml1.23snakeyaml-1.23.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-aop5.1.6.RELEASEspring-aop-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-beans5.1.6.RELEASEspring-beans-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgaspectjaspectjweaver1.9.2aspectjweaver-1.9.2.jar;D:installsoftmaven.m2
epository3.3.9_0orgprojectlomboklombok1.18.6lombok-1.18.6.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-starter-test2.1.4.RELEASEspring-boot-starter-test-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-test2.1.4.RELEASEspring-boot-test-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkootspring-boot-test-autoconfigure2.1.4.RELEASEspring-boot-test-autoconfigure-2.1.4.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0comjaywayjsonpathjson-path2.4.0json-path-2.4.0.jar;D:installsoftmaven.m2
epository3.3.9_0junitjunit4.12junit-4.12.jar;D:installsoftmaven.m2
epository3.3.9_0orgassertjassertj-core3.11.1assertj-core-3.11.1.jar;D:installsoftmaven.m2
epository3.3.9_0orgmockitomockito-core2.23.4mockito-core-2.23.4.jar;D:installsoftmaven.m2
epository3.3.9_0
etytebuddyyte-buddy1.9.12yte-buddy-1.9.12.jar;D:installsoftmaven.m2
epository3.3.9_0
etytebuddyyte-buddy-agent1.9.12yte-buddy-agent-1.9.12.jar;D:installsoftmaven.m2
epository3.3.9_0orgobjenesisobjenesis2.6objenesis-2.6.jar;D:installsoftmaven.m2
epository3.3.9_0orghamcresthamcrest-core1.3hamcrest-core-1.3.jar;D:installsoftmaven.m2
epository3.3.9_0orghamcresthamcrest-library1.3hamcrest-library-1.3.jar;D:installsoftmaven.m2
epository3.3.9_0orgskyscreamerjsonassert1.5.0jsonassert-1.5.0.jar;D:installsoftmaven.m2
epository3.3.9_0comvaadinexternalgoogleandroid-json.0.20131108.vaadin1android-json-0.0.20131108.vaadin1.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-core5.1.6.RELEASEspring-core-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-jcl5.1.6.RELEASEspring-jcl-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgspringframeworkspring-test5.1.6.RELEASEspring-test-5.1.6.RELEASE.jar;D:installsoftmaven.m2
epository3.3.9_0orgxmlunitxmlunit-core2.6.2xmlunit-core-2.6.2.jar;D:installsoftJavajdk1.8.0_121lib	ools.jar;E:yjd软 件Intellij IDEAideaIU-2017.1.5.winlibidea_rt.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.jvm.test6.Test 1 2
java.home = D:installsoftJavajdk1.8.0_121jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_121
java.ext.dirs = D:installsoftJavajdk1.8.0_121jrelibext;C:WindowsSunJavalibext
sun.boot.class.path = D:installsoftJavajdk1.8.0_121jrelib
esources.jar;D:installsoftJavajdk1.8.0_121jrelib
t.jar;D:installsoftJavajdk1.8.0_121jrelibsunrsasign.jar;D:installsoftJavajdk1.8.0_121jrelibjsse.jar;D:installsoftJavajdk1.8.0_121jrelibjce.jar;D:installsoftJavajdk1.8.0_121jrelibcharsets.jar;D:installsoftJavajdk1.8.0_121jrelibjfr.jar;D:installsoftJavajdk1.8.0_121jreclasses
java.vendor = Oracle Corporation
file.separator = 
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64

VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=1048576000 -XX:MaxNewSize=349175808 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=3145728 -XX:OldSize=7340032 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:64223,suspend=y,server=n -Xms10m -Xmx1000m -Dfile.encoding=UTF-8

jmap——java内存映射工具

jdk安装后会自带一些小工具,jmap命令(Memory Map for Java)是其中之一。主要用于打印指定Java进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。

jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等。可以使用jmap生成Heap Dump。

如果不想使用jmap命令,要想获取Java堆转储快照还有一些比较“暴力”的手段:譬如在前面用过的 -XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过-XX:+HeapDumpOnCtrlBreak参数可以使用[ctrl]+[Break]键让虚拟机生成dump文件,又或者在Linux系统下通过Kill -3 命令发送进程退出信息“恐吓”一下虚拟机,也能拿到dump文件。

jmap的作用并不仅仅是为了获取dump文件,他还可以查询finalize执行队列,java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。

jmap命令格式

[root@ady01 ~]# jmap
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
    -clstats             to print class loader 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

主要选项:

选项 作用
-dump 生成java堆转储快照,格式为:-dump:[live,]format=b,file=,其中live子参数说明是否只dump出存活对象
-finalizerinfo 显示在F-Queue中等待Finalizer线程执行finalize方法的对象,只在linux/solaris平台下有效
-heap 显示堆详细信息,如使用哪种回收期、参数配置、分带状况等,只在linux/solaris平台下有效
-histo 显示堆中对象统计信息,包括类、实例数量和合计容量
-permstat 以ClassLoader为统计口径显示永久代内存状况,只在linux/solaris平台下有效
-F 当虚拟机进程对-dump选项没有响应时,可以使用这个选项强制生成dump快照,只在linux/solaris平台下有效

jmap -dump:生成java堆转储快照

生成java对转存快照,格式:jmap -dump:[live,]format=b,file=文件名

C:UsersThink>jmap -dump:live,format=b,file=D:/dumptest.hprof 13984
Dumping heap to D:dumptest.hprof ...
Heap dump file created

可以使用jdk提供的jvisualvm.exe查看hprof文件

jmap -heap:显示堆详细信息

显示堆详细信息。

注意:使用时报错排查原因是由于机器上安装了多个jdk导致的。所以使用时要指定路径。

E:java8jdkinjmap -heap 13984

命令格式:jmap -heap

[root@ady01 ~]# jmap -heap 25867
Attaching to process ID 25867, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4164943872 (3972.0MB)
   NewSize                  = 87031808 (83.0MB)
   MaxNewSize               = 1388314624 (1324.0MB)
   OldSize                  = 175112192 (167.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 47710208 (45.5MB)
   used     = 2632072 (2.5101394653320312MB)
   free     = 45078136 (42.98986053466797MB)
   5.516790033696772% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 770128 (0.7344512939453125MB)
   free     = 278448 (0.2655487060546875MB)
   73.44512939453125% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 220200960 (210.0MB)
   used     = 98595728 (94.02821350097656MB)
   free     = 121605232 (115.97178649902344MB)
   44.77533976236979% used

38803 interned Strings occupying 4463232 bytes.

jmap -histo:显示堆中对象统计信息

显示堆中对象统计信息,包括类、实例数量和合计容量

命令格式:jmap -histo[:live]

C:UsersThink>jmap -histo 28252

 num     #instances         #bytes  class name
----------------------------------------------
   1:        309006       16963968  [C
   2:          1081        7275840  [I
   3:         41164        3156952  [B
   4:         90125        2163000  java.lang.String
   5:         21000         672000  java.util.UUID
   6:         21000         336000  com.jvm.test8.Test8$User
   7:         21000         336000  com.jvm.test8.Test8$User$UserBuilder
   8:           799         300072  [Ljava.lang.Object;
   9:          7557         181368  java.lang.StringBuilder
  10:           772          87704  java.lang.Class
  11:          1026          65664  sun.nio.fs.WindowsFileAttributes
  12:          1026          49248  sun.nio.fs.WindowsPath$WindowsPathWithAttributes
  13:           837          33480  java.util.TreeMap$Entry
  14:          1032          33024  java.lang.ref.WeakReference
  15:           775          31000  sun.nio.fs.WindowsPath
  16:          1028          24672  sun.nio.fs.WindowsPathParser$Result
  17:           424          13568  java.io.File
  18:           168          12096  java.lang.reflect.Field
  19:           299          11960  java.util.LinkedHashMap$Entry
  20:           323          11200  [Ljava.lang.String;
  21:           173          11072  java.net.URL
  22:           341          10912  sun.misc.FDBigInteger
  23:           312           9984  java.util.Hashtable$Entry
  24:            66           8992  [Ljava.util.HashMap$Node;
  25:           267           8544  java.util.HashMap$Node
  26:           195           7800  java.lang.ref.Finalizer
  27:           264           6336  java.lang.StringBuffer
  28:           121           4840  java.lang.ref.SoftReference
  29:            29           4816  [Ljava.util.Hashtable$Entry;
  30:            50           4800  java.util.jar.JarFile$JarFileEntry
  31:           105           4552  [[C
  32:            53           4240  [Ljava.util.WeakHashMap$Entry;
  33:            74           4144  sun.misc.URLClassPath$JarLoader
  34:           258           4128  java.lang.Integer
  35:            50           4000  java.util.zip.ZipEntry
  36:            79           3792  java.net.NetworkInterface
  37:           150           3600  java.net.Parts
  38:           111           3552  java.util.concurrent.ConcurrentHashMap$Node
  39:           134           3216  java.security.Provider$ServiceKey
  40:            50           3200  java.util.jar.JarFile
  41:            55           3080  sun.nio.cs.UTF_8$Encoder
  42:             8           3008  java.lang.Thread
  43:            62           2976  java.util.HashMap
  44:            51           2856  java.util.zip.ZipFile$ZipFileInputStream
  45:           114           2736  java.io.ExpiringCache$Entry
  46:            53           2544  java.util.WeakHashMap
  47:            30           2400  java.lang.reflect.Constructor
  48:            56           2240  java.util.WeakHashMap$Entry
  49:            39           2184  java.util.zip.ZipFile$ZipFileInflaterInputStream

疑问:

Q: 如何dump堆快照,如何使用jvisualvm.exe查看java进程上dump下来的hprof文件?

A: 首选,我们dump堆快照可以使用jmap命令手动dump下想要获取的堆快照。格式如下:

jmap -dump:[live,]format=b,file=文件名

jmap -dump:live,format=b,file=D:/1.hprof 24956

其次,如果不想使用jmap命令,要想获取Java堆转储快照还有一些比较“暴力”的手段:譬如在前面用过的 -XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过-XX:+HeapDumpOnCtrlBreak参数可以使用[ctrl]+[Break]键让虚拟机生成dump文件,又或者在Linux系统下通过Kill -3 命令发送进程退出信息“恐吓”一下虚拟机,也能拿到dump文件。

windows使用jvisualvm.exe查看java进程上dump操作如下:

1、进入jdk按照的bin目录打开jvisualvm.exe。

E:java8jdkin

2、点击文件装入取选取我们dump下的文件位置。注意要更改装入的文件类型为.hprof文件。

3、切换到类选型就可以查看当前dump文件中存活的类占比较大的是什么对象。从而进一步分析内存溢出的原因。

jhat——虚拟机堆转储快照分析工具——一般很少用这个,而是用集成工具

jhat也是jdk内置的工具之一。主要是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言。

使用jmap等方法生成java的堆文件后,使用其进行分析

示例:

1.运行代码:

package com.jvm.test8;

import lombok.*;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class Test8 {
    @Getter
    @Setter
    @ToString
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class User {
        private String name;
    }

    public static void main(String[] args) throws InterruptedException {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 3000; i++) {
            for (int j = 0; j < 1000; j++) {
                list.add(User.builder().name(UUID.randomUUID().toString()).build());
            }
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

2.导出程序执行的堆信息——jmap

F:fcargitnewhellospringboot>jps -l
13984
12468 sun.tools.jps.Jps
6324 org.jetbrains.jps.cmdline.Launcher
6908 com.self.test.Test2
8908 org.jetbrains.idea.maven.server.RemoteMavenServer

F:fcargitnewhellospringboot>jmap -dump:live,format=b,file=D:/dump.hprof 6908
Dumping heap to D:dump.hprof ...
Heap dump file created

3.使用jhat分析堆文件

F:fcargitnewhellospringboot>jmap -dump:live,format=b,file=D:/dump.hprof 6908
Dumping heap to D:dump.hprof ...
Heap dump file created

F:fcargitnewhellospringboot>jhat D:/dump.hprof
Reading from D:/dump.hprof...
Dump file created Mon Oct 19 11:21:10 CST 2020
Snapshot read, resolving...
Resolving 179681 objects...
Chasing references, expect 35 dots...................................
Eliminating duplicate references...................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

4.查看html

分析内存泄露问题主要会用到“Show heap histogram”“”和“OQL”,前者可以找到内存中总容量最大的对象,后者是标准的对象查询语言,使用类似于SQL的语法对内存对象进行查询统计。

  • 显示出堆中所包含的所有的类
  • 从根集能引用到的对象
  • 显示所有类(包括平台)的实例计数
  • 堆实例的分布表
  • 执行对象查询语句

输入内容如:

查询长度大于100的字符串

select s from java.lang.String s where s.count > 100

详细的OQL可点击上图的“OQL help”

jhat中的OQL(对象查询语言) ,文档可以查看:http://localhost:7000/oqlhelp/
如果需要根据某些条件来过滤或查询堆的对象,这是可能的,可以在jhat的html页面中执行OQL,来查询符合条件的对象

基本语法: 
select <javascript expression to select>
[from [instanceof] <class name> <identifier>]
[where <javascript boolean expression to filter>]

解释: 
(1)class name是java类的完全限定名,如:java.lang.String, java.util.ArrayList, [C是char数组, [Ljava.io.File是java.io.File[]
(2)类的完全限定名不足以唯一的辨识一个类,因为不同的ClassLoader载入的相同的类,它们在jvm中是不同类型的
(3)instanceof表示也查询某一个类的子类,如果不明确instanceof,则只精确查询class name指定的类
(4)from和where子句都是可选的
(5)java域表示:obj.field_name;java数组表示:array[index]

举例: 
(1)查询长度大于100的字符串
select s from java.lang.String s where s.count > 100

(2)查询长度大于256的数组
select a from [I a where a.length > 256

(3)显示匹配某一正则表达式的字符串
select a.value.toString() from java.lang.String s where /java/(s.value.toString())

(4)显示所有文件对象的文件路径
select file.path.value.toString() from java.io.File file

(5)显示所有ClassLoader的类名
select classof(cl).name from instanceof java.lang.ClassLoader cl

(6)通过引用查询对象
select o from instanceof 0xd404d404 o

built-in对象 -- heap 
(1)heap.findClass(class name) -- 找到类
select heap.findClass("java.lang.String").superclass

(2)heap.findObject(object id) -- 找到对象
select heap.findObject("0xd404d404")

(3)heap.classes -- 所有类的枚举
select heap.classes

(4)heap.objects -- 所有对象的枚举
select heap.objects("java.lang.String")

(5)heap.finalizables -- 等待垃圾收集的java对象的枚举

(6)heap.livepaths -- 某一对象存活路径
select heaplivepaths(s) from java.lang.String s

(7)heap.roots -- 堆根集的枚举

辨识对象的函数 
(1)classof(class name) -- 返回java对象的类对象
select classof(cl).name from instanceof java.lang.ClassLoader cl

(2)identical(object1,object2) -- 返回是否两个对象是同一个实例
select identical(heap.findClass("java.lang.String").name, heap.findClass("java.lang.String").name)

(3)objectid(object) -- 返回对象的id
select objectid(s) from java.lang.String s

(4)reachables -- 返回可从对象可到达的对象
select reachables(p) from java.util.Properties p -- 查询从Properties对象可到达的对象
select reachables(u, "java.net.URL.handler") from java.net.URL u -- 查询从URL对象可到达的对象,但不包括从URL.handler可到达的对象

(5)referrers(object) -- 返回引用某一对象的对象
select referrers(s) from java.lang.String s where s.count > 100

(6)referees(object) -- 返回某一对象引用的对象
select referees(s) from java.lang.String s where s.count > 100

(7)refers(object1,object2) -- 返回是否第一个对象引用第二个对象
select refers(heap.findObject("0xd4d4d4d4"),heap.findObject("0xe4e4e4e4"))

(8)root(object) -- 返回是否对象是根集的成员
select root(heap.findObject("0xd4d4d4d4")) 

(9)sizeof(object) -- 返回对象的大小
select sizeof(o) from [I o

(10)toHtml(object) -- 返回对象的html格式
select "<b>" + toHtml(o) + "</b>" from java.lang.Object o

(11)选择多值
select {name:t.name?t.name.toString():"null",thread:t} from instanceof java.lang.Thread t

数组、迭代器等函数 
(1)concat(enumeration1,enumeration2) -- 将数组或枚举进行连接
select concat(referrers(p),referrers(p)) from java.util.Properties p

(2)contains(array, expression) -- 数组中元素是否满足某表达式
select p from java.util.Properties where contains(referres(p), "classof(it).name == 'java.lang.Class'")
返回由java.lang.Class引用的java.util.Properties对象
built-in变量
it -- 当前的迭代元素
index -- 当前迭代元素的索引
array -- 被迭代的数组

(3)count(array, expression) -- 满足某一条件的元素的数量
select count(heap.classes(), "/java.io./(it.name)")

(4)filter(array, expression) -- 过滤出满足某一条件的元素
select filter(heap.classes(), "/java.io./(it.name)")

(5)length(array) -- 返回数组长度
select length(heap.classes())

(6)map(array,expression) -- 根据表达式对数组中的元素进行转换映射
select map(heap.classes(),"index + '-->' + toHtml(it)")

(7)max(array,expression) -- 最大值, min(array,expression)
select max(heap.objects("java.lang.String"),"lhs.count>rhs.count")
built-in变量
lhs -- 左边元素
rhs -- 右边元素

(8)sort(array,expression) -- 排序
select sort(heap.objects('[C'),'sizeof(lhs)-sizeof(rhs)')

(9)sum(array,expression) -- 求和
select sum(heap.objects('[C'),'sizeof(it)')

(10)toArray(array) -- 返回数组

(11)unique(array) -- 唯一化数组

jstack——java栈跟踪工具

jstack介绍

jstack(stack trace for java)是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式:

jstack [-l] pid

主要分为两个功能:

  1. 针对活着的进程做本地的或远程的线程dump
  2. 针对core文件做线程dump

jstack用于生成java虚拟机当前时刻的线程快照。

线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。

另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

So,jstack命令主要用来查看Java线程的调用堆栈的,可以用来分析线程问题(如死锁)。

线程状态

想要通过jstack命令来分析线程的情况的话,首先要知道线程都有哪些状态,下面这些状态是我们使用jstack命令查看线程堆栈信息时可能会看到的线程的6种状态:

  1. NEW:未启动的。不会出现在Dump中。
  2. RUNNABLE:在虚拟机内执行的。运行中状态,可能里面还能看到locked字样,表明它获得了某把锁。
  3. BLOCKED:受阻塞并等待监视器锁。被某个锁(synchronizers)給block住了。
  4. WATING:无限期等待另一个线程执行特定操作。等待某个condition或monitor发生,一般停留在park(), wait(),sleep(),join() 等语句里。
  5. TIMED_WATING:有时限的等待另一个线程的特定操作。和WAITING的区别是wait() 等语句加上了时间限制 wait(timeout)。
  6. TERMINATED:已退出的。

关于线程状态,具体也可以查看:java.lang.Thread.State类。

Monitor(监视器)

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

  1. 进入区(Entrt Set):表示线程通过synchronized要求获取对象的锁。如果对象未被锁住(即获得到锁),则进入拥有者;否则则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。
  2. 拥有者(The Owner):表示某一线程成功竞争到对象锁。
  3. 等待区(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) {
    //.........
}

调用修饰

表示线程在方法调用时,额外的重要的操作。线程Dump分析的重要信息。修饰上方的方法调用。

locked <地址> 目标:使用synchronized申请对象锁成功,监视器的拥有者。

waiting to lock <地址> 目标:使用synchronized申请对象锁未成功,在进入区等待。

waiting on <地址> 目标:使用synchronized申请对象锁成功后,释放锁并在等待区等待。

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

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

通过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

通过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

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

parking to wait for

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

线程动作

线程状态产生的原因:

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

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

jstack命令格式

jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP

常用参数说明

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)基本参数:

  1. -F :当’jstack [-l] pid’没有响应的时候,强制打印线程堆栈信息,一般情况不需要使用
  2. -l :长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表,会使得JVM停顿得长久得多(可能会差很多倍,比如普通的jstack可能几毫秒和一次GC没区别,加了-l 就是近一秒的时间),-l 建议不要用,一般情况不需要使用
  3. -m : 打印java和native c/c++框架的所有栈信息.可以打印JVM的堆栈,显示上Native的栈帧,一般应用排查不需要使用
  4. -h | -help :打印帮助信息
  5. pid :需要被打印配置信息的java进程id,可以用jps查询

使用示例

jstack pid

~$ jps -ml
org.apache.catalina.startup.Bootstrap 
~$ jstack 5661
2013-04-16 21:09:27
Full thread dump Java HotSpot(TM) Server VM (20.10-b01 mixed mode):

"Attach Listener" daemon prio=10 tid=0x70e95400 nid=0x2265 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"http-bio-8080-exec-20" daemon prio=10 tid=0x08a35800 nid=0x1d42 waiting on condition [0x70997000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x766a27b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:399)
    at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:104)
    at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:32)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
    at java.lang.Thread.run(Thread.java:662)
........

死循环

  1. 写个死循环代码
    package com.jvm.jstack;

     /**
      * <a href="http://www.itsoku.com/archives">Java干货铺子,只生产干货,公众号:javacode2018</a>
      */
     public class Demo1 {
         public static void main(String[] args) {
             while (true) {
             }
         }
     }
    
  2. 运行代码

  3. cmd中执行jps查看程序进程id
    F:fcargitnewhellospringboot>jps
    13984
    11060 Test2
    12916 Launcher
    396 Jps
    8908 RemoteMavenServer

    进程id为 11060

  4. 输入jstack 11060命令,找到跟我们自己代码相关的线程,如下为main线程,处于runnable状态,在main方法的第8行,也就是我们死循环的位置.
    jstack 11060

    "main" #1 prio=5 os_prio=0 tid=0x0000000002a37000 nid=0x2c50 runnable [0x000000000282f000]
       java.lang.Thread.State: RUNNABLE
            at com.self.test.Test2.main(Test2.java:46)
    

Object.wait()情况

执行下列代码:

package com.jvm.jstack;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <a href="http://www.itsoku.com/archives">Java干货铺子,只生产干货,公众号:javacode2018</a>
 */
public class Demo2 {
    static class TestTask implements Runnable {
        @Override
        public void run() {

            synchronized (this) {
                try {
                    //等待被唤醒
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) {
        ExecutorService ex = Executors.newFixedThreadPool(1);
        ex.execute(new TestTask());
    }
}


"From DemoThreadFactory's 订单创建组-Worker-1" #11 prio=5 os_prio=0 tid=0x000000001e476000 nid=0x13f0 in Object.wait() [0x000000001f12e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076b798240> (a com.self.test.Test3$TestTask)
        at java.lang.Object.wait(Object.java:502)
        at com.self.test.Test3$TestTask.run(Test3.java:28)
        - locked <0x000000076b798240> (a com.self.test.Test3$TestTask)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

死锁情况

  1. 写个死锁的例子
    public class TestDeadLock {

        private static Object obj1 = new Object();
        private static Object obj2 = new Object();
    
        public static void main(String[] args) {
            //自定义饱和策略
            ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 600,
                    TimeUnit.SECONDS, new LinkedBlockingQueue<>(5),
                    new DemoThreadFactory("订单创建组"), new ThreadPoolExecutor.AbortPolicy());
            // 起10个线程
            for (int i = 0; i < 10; i++) {
                int order = i % 2 == 0 ? 1 : 0;
                executor.execute(new MyRunnable(order));
            }
        }
    
        static class MyRunnable implements Runnable{
            private int order;
    
            public MyRunnable( int order) {
                this.order = order;
            }
    
            public void test1() throws InterruptedException {
                synchronized (obj1) {
                    synchronized (obj2) {
                        System.out.println("test1。。。");
                    }
                }
            }
    
            public void test2() throws InterruptedException {
                synchronized (obj2) {
                    synchronized (obj1) {
                        System.out.println("test2。。。");
                    }
                }
            }
    
            @Override
            public void run() {
                while (true) {
                    try {
                        if (this.order == 1) {
                            this.test1();
                        } else {
                            this.test2();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  2. 运行上面代码产生死锁.

  3. 我们先通过jsp查找到程序的进程,然后通过jstack查看线程堆栈,很快就可以发现死锁
    Found one Java-level deadlock:
    =============================
    "From DemoThreadFactory's 订单创建组-Worker-10":
    waiting to lock monitor 0x000000001c46dfa8 (object 0x000000076b77cf68, a java.lang.Object),
    which is held by "From DemoThreadFactory's 订单???建组-Worker-4"
    "From DemoThreadFactory's 订单创建组-Worker-4":
    waiting to lock monitor 0x000000001c46f448 (object 0x000000076b77cf58, a java.lang.Object),
    which is held by "From DemoThreadFactory's 订单创建组-Worker-5"
    "From DemoThreadFactory's 订单创建组-Worker-5":
    waiting to lock monitor 0x000000001c46dfa8 (object 0x000000076b77cf68, a java.lang.Object),
    which is held by "From DemoThreadFactory's 订单创建组-Worker-4"

    Java stack information for the threads listed above:
    ===================================================
    "From DemoThreadFactory's 订单创建组-Worker-10":
            at com.self.test.TestDeadLock$MyRunnable.test2(TestDeadLock.java:55)
            - waiting to lock <0x000000076b77cf68> (a java.lang.Object)
            at com.self.test.TestDeadLock$MyRunnable.run(TestDeadLock.java:68)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at java.lang.Thread.run(Thread.java:748)
    "From DemoThreadFactory's 订单创建组-Worker-4":
            at com.self.test.TestDeadLock$MyRunnable.test2(TestDeadLock.java:56)
            - waiting to lock <0x000000076b77cf58> (a java.lang.Object)
            - locked <0x000000076b77cf68> (a java.lang.Object)
            at com.self.test.TestDeadLock$MyRunnable.run(TestDeadLock.java:68)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at java.lang.Thread.run(Thread.java:748)
    "From DemoThreadFactory's 订单创建组-Worker-5":
            at com.self.test.TestDeadLock$MyRunnable.test1(TestDeadLock.java:48)
            - waiting to lock <0x000000076b77cf68> (a java.lang.Object)
            - locked <0x000000076b77cf58> (a java.lang.Object)
            at com.self.test.TestDeadLock$MyRunnable.run(TestDeadLock.java:66)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at java.lang.Thread.run(Thread.java:748)
    
    Found 1 deadlock.
    

等待io

  1. 运行代码
    public class TestIO {
    public static void main(String[] args) throws IOException {
    InputStream is = System.in;
    int i = is.read();
    System.out.println("exit。");
    }
    }

  2. 和上面一样,jps获取进程,jstack获取线程堆栈信息
    //长列表. 打印关于锁的附加信息
    jstack -l 9168

    "main" #1 prio=5 os_prio=0 tid=0x00000000029b7000 nid=0xee0 runnable [0x000000000281f000]
       java.lang.Thread.State: RUNNABLE
            at java.io.FileInputStream.readBytes(Native Method)
            at java.io.FileInputStream.read(FileInputStream.java:255)
            at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
            at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
            - locked <0x000000076b4614f8> (a java.io.BufferedInputStream)
            at com.self.test.TestIO.main(TestIO.java:19)
    
       Locked ownable synchronizers:
            - None
    

疑问:

Q: Wait on condition 该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stack trace来分析。 最常见的情况就是线程处于sleep状态,等待被唤醒。 这应该是wait状态,等待被唤醒,而不是sleep状态吧?

原文地址:https://www.cnblogs.com/castamere/p/13844022.html