第2章 JVM监控及诊断工具_COMMAND篇

第1章 JVM调优前言篇
第2章 JVM监控及诊断工具_COMMAND篇
第3章 JVM监控及诊断工具_GUI篇
第4章 JVM运行时参数篇
第5章 JVM中GC日志分析篇


https://docs.oracle.com/javase/8/javase-books.htm
https://docs.oracle.com/javase/8/docs/technotes/tools/index.html

1 最前面的小尾巴

  1. 使用数据说明问题,使用知识分析问题,使用工具处理问题。
  2. 无监控、不调优!
    jdk提供的工具: C:\dev\Java\jdk1.8.0_191\bin
    https://hg.openjdk.org/jdk/jdk11/file/1ddf9a99e4ad/src/jdk.jcmd/share/classes/sun/tools

2 jps 查看正在运行的Java进程

2.1 说明

jps(Java Process Status) :查看指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。
对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,且是唯一的。

2.2 Try It

测试类:com.michael.commandtest.jps.ScannerTest
在这里插入图片描述

2.3 语法详情

jps [options] [hostid]

jps
jps -l
jps -lv

在这里插入图片描述
1、options参数              
-q:仅仅显示LVMID (local virtual machine id),即本地虚拟机唯一id。不显示主类的名称等。
-l:显示应用程序主类的 全类名 或 如果进程执行的是jar包,则输出 jar完整路径
-m:显示虚拟机进程启动时传递给主类main()的 参数
-v:显示虚拟机进程启动时的JVM参数。 如: -Xms20m -Xmx50m 是启动程序指定的jvm参数。
!!!!! 以上参数可以综合使用。

注:如果某 Java 进程关闭了默认开启的 UsePerfData 参数(即使用参数 -XX:-UsePerfData 关闭) ,那么 jpsjstat 命令将无法探知该Java 进程(-XX:+UsePerfData 开启)。

jps -l -m
等价于
jps -lm
如何将信息输出到同级文件中:命令 > 文件名称
jps -lmv > a.txt

2、hostid参数              
RMI注册表中注册的主机名。如果想要远程监控主机上的 java 程序,需要安装 jstatd。

对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到IP地址欺诈攻击

如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行 jstatd 服务器,而是在本地使用 jstatjps 工具。

3 jstat 查看JVM统计信息

3.1 说明

jstat (JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期间定位虚拟机性能问题的首选工具。常用于检测 垃圾回收问题内存泄漏问题

官方文档:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

3.2 Try It

[root@VM-0-5-centos ~]$ 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.

3.2.1 options 参数

[root@VM-0-5-centos ~]$ jstat -options
-class	类装载相关;显示ClassLoader的相关信息:类的装载、卸载数量、总空间、类装载所消耗的时间等。
-compiler	JIT相关;显示JIT编译器编译过的方法、耗时等信息-printcompilation: 输出已经被JIT编译的方法。

-gc			垃圾回收相关;显示与GC相关的堆信息。包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息。
-gccapacity	垃圾回收相关;显示内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间。
-gcutil		垃圾回收相关;显示内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比。
-gccause	垃圾回收相关;与-gcutil功能一样,但是会额外输出导致最后一次或当前正在发生的GC产生的原因。

-gcnew			垃圾回收相关;显示新生代GC状况。
-gcnewcapacity	垃圾回收相关;显示内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间。

-gcold			垃圾回收相关;显示老年代GC状况。
-gcoldcapacity	垃圾回收相关;显示内容与-gcold基本相同,输出主要关注使用到的最大、最小空间。

-gcmetacapacity	垃圾回收相关;java8 显示永久代使用到的最大、最小空间。 -gcpermcapacity	显示永久代使用到的最大、最小空间。
-printcompilation
3.2.1.1 -class demo
jstat -class -t -h2 13728 1000 5

其中h2中的2代表每隔2条记录分隔显示一次表头;13728代表类的进程id;1000代表每隔1000毫秒打印一次;5代表一共打印5次;如下所示:
在这里插入图片描述

Timestamp 代表程序至今的运行时间,单位为秒;
Loaded 代表加载的类的数目;
Bytes 代表加载的类的总字节数;
Unloaded 代表卸载的类的数目;
Bytes 代表卸载的类的总字节数;
Time 代表类装载所消耗的时间;

3.2.1.2 -gc demo

com.michael.commandtest.jstat.GCTest

jstat -gc 12860 1000 7

其中12860代表类的进程id,执行结果如下所示:
在这里插入图片描述

  • 新生代相关:
    S0C 代表幸存者0区的总容量大小(字节)。
    S1C 代表幸存者1区的总容量大小(字节)。
    S0U 代表幸存者0区使用的容量大小(字节)。
    S1U 代表幸存者1区使用的容量大小(字节)。
    EC 代表伊甸园区的总容量大小(字节)。
    EU 代表伊甸园区使用的总容量大小(字节)。

  • 老年代相关:
    OC 代表老年代的总容量大小(字节)。
    OU 代表老年代已经使用的容量大小(字节)。

  • 方法区(元空间)相关:
    MC 代表方法区的总容量。
    MU 代表方法区的总容量。
    CCSC 代表压缩类的总容量。
    CCSU 代表压缩类使用的容量。

  • 垃圾回收相关:
    YGC 代表年轻代垃圾回收的次数【从应用程序启动到采样时young gc的次数】。
    YGCT 年轻代进行垃圾回收需要的时间【从应用程序启动到采样时young gc消耗时间(秒)】。
    FGC 代表代表Full GC的次数【从应用程序启动到采样时full gc的次数】。
    FGCT 代表Full GC的时间【从应用程序启动到采样时的full gc的消耗时间(秒)】。
    GCT 代表垃圾回收的总时间【从应用程序启动到采样时gc的总时间】。

3.2.1.3 -gccapacity demo

com.michael.commandtest.jstat.GCTest

jstat -gccapacity 20368

其中20368代表类的进程id,执行结果如下:
在这里插入图片描述

S0C 代表幸存者0区的容量。
S1C 代表幸存者1区的容量。
EC 代表伊甸园区的容量。
CCSC 代表压缩类的容量。
YGC 代表年轻代垃圾回收的时间。
FGC 代表 Full GC 垃圾回收的时间。

3.2.1.4 -gcutil demo

com.michael.commandtest.jstat.GCTest

jstat -gcutil 20368 1000 5

其中20368 代表类的进程id,执行结果如下所示:
在这里插入图片描述

以上是各区域占比以及垃圾回收的情况,
S0 代表幸存者0区 占比情况。
S1 代表幸存者1区 占比情况。
E 代表伊甸园区 占比情况。
O 代表老年代 占比情况。
M 代表方法区 占比情况。
CCS 代表压缩类 占比情况。

YGC 代表年轻代垃圾回收的次数。
YGCT 年轻代进行垃圾回收需要的时间。
FGC 代表代表Full GC的次数。
FGCT 代表Full GC的时间。
GCT 代表垃圾回收的总时间;GCT+FGCT=GCT

3.2.1.5 -gccause demo

com.michael.commandtest.jstat.GCTest

jstat -gccause 18364 20000 10

其中17612代表类的进程id,执行结果如下:
在这里插入图片描述

以上是各区域占比以及垃圾回收的情况,还有触发垃圾回收的原因解释,
S0 代表幸存者0区。
S1 代表幸存者1区。
E 代表伊甸园区。
O 代表老年代。
M 代表方法区。
CCS 代表压缩类,以上这些值都是占比情况。

YGC 代表年轻代垃圾回收的次数。
YGCT 年轻代进行垃圾回收需要的时间。
FGC 代表代表Full GC的次数。
FGCT 代表Full GC的时间。
GCT 代表垃圾回收的总时间。
LGCCGCC 代表垃圾回收的原因。

3.2.1.6 -compiler demo 和 -printcompilation demo

com.michael.commandtest.jstat.GCTest

//编译了多少类的相关信息
jstat -compiler 8880
//编译了多少类的方法相关信息
jstat -printcompilation 8880

在这里插入图片描述

3.2.2 interval 参数

用于指定输出统计数据的周期,单位为毫秒。即:查询间隔。

3.2.3 count 参数

用于指定查询的总次数。

3.2.4 -t 参数

可以在输出信息前加上一个 Timestamp列,显示程序的运行时间。单位:秒。

经验总结:
我们可以比较 Java 进程的启动时间以及总 GC 时间 (GCT 列),或者两次测量的间隔时间以及总 GC 时间的增量,来得出 GC 时间占运行时间的比例。
如果该比例超过 20%,则说明目前堆的压力较大:如果该比例超过 90%,则说明堆里几乎没有可用空间,随时都可能抛出 OOM 异常。

执行 jstat -gc -t 21232 30000 10,结果如下所示:
在这里插入图片描述

上方红色框框中代表Timestamp,而蓝色框框中代表垃圾回收时间,单位都是秒,如果让红色框框中的某两个值相减,假设这个值是num1,然后让对应行的蓝色框框中的另外两个值相减,假设这个值是num2,之后让 num2/num1,得出的结果值就是上述所说的 GC时间占运行时间的比例

注:在实际项目部署之后就没有可视化界面了,就需要使用命令行去看,所以这种方式一定要会。

3.2.5 -h 参数

可以在周期性数据输出时,输出多少行数据后输出一个表头信息。

3.3 经验【jstat判断是否出现内存泄漏】

  1. 在长时间运行的 Java 程序中,我们可以运行jstat命令连续获取多行性能数据,并取这几行数据中 OU 列(即已占用的老年代内存) 的最小值。jstat -gc -t 16582 30000 10
  2. 然后,我们每隔一段较长的时间重复一次上述操作,来获得多组 OU 最小值。如果这些值呈上涨趋势,则说明该 Java 程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。jstat -gc -t 16582 30000 10

4 jinfo 实时查看和修改JVM配置参数

4.1 说明

jinfo(Configuration Info for Java)查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数。
在很多情况,Java应用程序不会指定所有的Java虚拟机参数。而此时,开发人员可能不知道某一个具体的Java虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo工具,开发人员可以很方便地找到Java虚拟机参数的当前值。

在这里插入图片描述
官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jinfo.html

4.2 Try It

基本使用语法说明: jinfo 命令必须 跟 java进程ID
jinfo [option] <pid>
options选项选项说明
no option输出全部的参数和系统属性。
-flag name输出对应名称的参数。
-flag [+-]name开启或者关闭对应名称的参数,只有被标记为manageable的参数才可以被动态修改
-flag name=value设定对应名称的参数。
-flags输出全部的参数。
-sysprops输出系统属性。

4.2.1 jinfo -sysprops 进程id

可以查看由System.getProperties()取得的参数。

jinfo -sysprops 27836

在这里插入图片描述

4.2.2 jinfo -flags 进程id

查看曾经赋过值的一些参数。

jinfo -flags 27836

在这里插入图片描述

4.2.3 jinfo -flag 参数名称 进程id

查看某个java进程的具体参数信息。

jinfo -flag UseParallelGC 27836
jinfo -flag UseSerialGC 27836
jinfo -flag UseG1GC 27836

在这里插入图片描述

jinfo不仅可以查看运行时某一个Java虚拟机参数的实际取值,甚至可以在运行时修改部分参数,并使之立即生效。
但是,并非所有参数都支持动态修改。参数只有被标记为manageable的flag可以被实时修改。其实,这个修改能力是极其有限的。查看被标记为manageable的参数命令如下

java -XX:+PrintFlagsFinal -version | grep manageable

在这里插入图片描述

  • 针对boolean类型
jinfo -flag [+|-]参数名称 <进程id>

修改:jinfo -flag +PrintGCDetails 24312
查看:jinfo -flag PrintGCDetails 24312
修改:jinfo -flag -PrintGCDetails 24312
查看:jinfo -flag PrintGCDetails 24312

使用 + 号,可以让该参数起作用。
使用 - 号,可以让参数不起作用。具体例子如下:
在这里插入图片描述

  • 针对key=value类型
jinfo -flag <参数名称=参数值> <进程id>

查看:jinfo -flag MaxHeapFreeRatio 24312
查看:jinfo -flag MaxHeapFreeRatio=91 24312
查看:jinfo -flag MaxHeapFreeRatio 24312

在这里插入图片描述

查看所有JVM参数启动的初始值

java -XX:+PrintFlagsInitial

在这里插入图片描述

查看所有JVM参数的最终值

值前面添加 冒号: 的是修改之后的值,没有添加的都是没有发生改变的初始值
java -XX:+PrintFlagsFinal

在这里插入图片描述

查看那些已经被用户或者JVM设置过的详细的XX参数的名称和值

java -参数名称:+PrintCommandLineFlags

5 jmap 导出内存像文件&内存使用情况

5.1 说明

jmap(JVM Memory Map):作用一方面是获取dump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
开发人员可以在控制台中输入命令“jmap -help”查阅jmap工具的具体使用方式和一些标准选项配置。
官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jmap.html

在这里插入图片描述
<executable 代表可执行的代码,比如使用> 文件名称来指定生成的dump文件的生成位置
[server_id@]<……>是为远程连接准备的

它的基本使用语法为:

jmap [option] <pid>
jmap [option]<executable <core>
jmap [option][server_id@]<remote server IP or hostname>

其中options包括:

选项作用
-dump(重要)生成Java堆转储快照:dump文件。(特别的:-dump:live只保存堆中的存活对象)
-heap (重要)输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等
-histo (重要)输出堆空间中对象的统计信息,包括类、实例数量和合计容量(特别的:-histo:live只统计堆中的存活对象)
-permstat【仅linux/solaris平台有效】以ClassLoader为统计口径输出永久代的内存状态信息
-finalizerinfo【仅linux/solaris平台有效】显示在F-Queue中等待Finalizer线程执行finalize方法的对象
-F【仅linux/solaris平台有效】当虚拟机进程对-dump选项没有任何响应时,强制执行生成dump文件
-J <flag>传递参数给jmap启动的jvm

说明: 这些参数和linux下输入显示的命令多少会有不同,包括也受jdk版本的影响。

5.2 Try It

使用语法可以通过在DOS窗口中使用jmap/jmap -h/jmap -help查看

5.2.1 导出内存映像文件

一般来说,使用jmap指令生成dump文件的操作算得上是最常用的jmap命令之一,将堆中所有存活对象导出至一个文件之中。
Heap Dump又叫做堆存储文件,指一个Java进程在某个时间点的内存快照。Heap Dump在触发内存快照的时候会保存此刻的信息如下:

All Objects
Class,fields,primitive values and references 

All Classes
ClassLoader,name,super class,static fields

Garbage Collection Roots
Objects defined to be reachable by the JVM 

Thread Stacks and Local Variables
The call-stacks of threads at the moment of the snapshot,and per-frameinformation about local objects

说明:
1.通常在写Heap Dump文件前会触发一次FulI GC,所以heap dump文件里保存的都是FullGC后留下的对象信息。
2.由于生成dump文件比较耗时,因此大家需要耐心等待,尤其是大内存镜像生成dump文件则需要耗费更长的时间来完成。

注意:
1、对于以上说明中的第1点是自动方式才会这样做,而手动不会在Full GC之后生成Dump。
2、使用手动方式生成dump文件,一般指令执行之后就会生成,不用等到快出现OOM的时候。
3、使用自动方式生成dump文件,当出现OOM之前先生成dump文件。
4、如果使用手动方式,一般使用第2种,毕竟生成堆中存活对象的dump文件是比较小的,便于传输和分析。

5.2.1.1 jmap手动导出方式

jmap -dump:format=b,file=<filename.hprof> <pid>
jmap -dump:live,format=b,file=<filename.hprof> <pid>

说明:
<filename.hprof>中的 filename 是文件名称,而 .hprof 是后缀名, <***> 代表该值可以省略 <>,当然后面的 <pid> 是进程id,需要通过 jps 查询出来。
format=b 表示生成的是标准的dump文件,用来进行格式限定。

1、生成堆中所有对象的快照:

jmap -dump:format=b,file=d:\11.hprof 10256

在这里插入图片描述
其中 file=指定生成的dump文件的地址,最后的10256是进程id。

2、生成堆中存活对象的快照:

jmap -dump:live,format=b,file=d:\22.hprof 10256

在这里插入图片描述
其中 file=指定生成的dump文件的地址,最后的10256是进程id。

一般使用的是第二种方式,也就是生成堆中存活对象的快照,毕竟这种方式生成的dump文件更小,我们传输处理都更方便。

5.2.1.2 jmap自动的方式

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<filename.hprof>
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\m20230321.hprof

当程序发生OOM退出系统时,一些瞬时信息都随着程序的终止而消失,而重现OOM问题往往比较困难或者耗时。此时若能在OOM时,自动导出dump文件就显得非常迫切。

-XX:+HeapDumpOnOutOfMemoryError:在程序发生OOM时,导出应用程序的当前堆快照。
-XX:HeapDumpPath:指定堆快照的保存位置。

5.2.2 显示堆内存相关信息

jmap -heap <进程id>
jmap -heap 28560 > aa.txt

jmap -heap 进程id只是时间点上的堆信息,而jstat后面可以添加参数,可以指定时间动态观察数据改变情况,而图形化界面工具,例如jvisualvm等,它们可以用图表的方式动态展示出相关信息,更加直观明了。


jmap -histo <进程id>
jmap -histo 28560 > bb.txt

输出堆中对象的同级信息,包括类、实例数量和合计容量,也是这一时刻的内存中的对象信息。

5.2.3 其他作用

// 查看系统的ClassLoader信息
jmap -permstat <进程id>

// 查看堆积在finalizer队列中的对象
jmap -finalizerinfo

这两个指令仅 linux/solaris 平台有效,所以无法在windows操作平台上演示,并且使用比较小众,不在多说了哦。

5.2.4 小结

由于 jmap 将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由 jmap 导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。

举个例子,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么 :live 选项将无法探知到这些对象。

另外,如果某个线程长时间无法跑到安全点,jmap 将一直等下去。

与前面讲的jstat则不同垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而 jstat只需直接读取即可。

6 jhat(jdk9已废弃)

jhat(JVM Heap Analysis Tool):Sun JDK提供的jhat命令与jmap命令搭配使用,用于分析jmap生成的heap dump文件(堆转储快照)。jhat内置了一个微型的HTTP/HTML服务器, 生成dump文件的分析结果后, 用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)。

使用了jhat命令,就启动了一个http服务,端口是7000,即 http://localhost:7000/ 就可以在浏览器里分析。

说明: jhat命令在JDK9、JDK19中已经被删除,官方建议用VisualVM代替。

7 jstack 打印JVM中线程快照

7.1 说明

jstack(JVM Stack Trace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。 线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。

生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用istack显示各个线程调用的堆栈情况。

官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jstack.html

在thread dump中,要留意下面几种状态:

  • 死锁,Deadlock(重点关注)
  • 等待资源,Waiting on condition(重点关注)
  • 等待获取监视器,Waiting on monitor entry(重点关注)
  • 阻塞,Blocked(重点关注)
  • 执行中,Runnable
  • 暂停,Suspended
  • 对象等待中,Object.wait() 或 TIMED WAITING
  • 停止,Parked

在这里插入图片描述

基本语法:
jstack <options> <pid>

jstack管理远程进程的话,需要在远程程序的启动参数中增加:
-Djava.rmi.server.hostname=xx.xx.xx.xx
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8888
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

只需要在TOMCAT_HOME/bin/找到catalina.sh 加上以下参数,重新启动tomcat就可以了: 
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.8.7 
					  -Dcom.sun.management.jmxremote.port=8088 
					  -Dcom.sun.management.jmxremote.ssl=false 
					  -Dcom.sun.management.jmxremote.authenticate=false"

option参数:
-F 当正常输出的请求不被响应时,强制输出线程堆栈。
-l 除堆栈外,显示关于锁的附加信息。
-m 如果调用本地方法的话,可以显示C/C++的堆栈。
-h 帮助操作。

7.2 Try It

jstack 14300 > aa.txt
jstack -l 14300 > bb.txt

在这里插入图片描述

总结:如果程序出现等待问题,可以使用该指令去查看问题所在,结果中也会提示你问题所在。

8 jcmd 多功能命令行

8.1 说明

一个顶多个,真的很强。在JDK 1.7以后,新增了一个命令行工具jcmd。它是一个多功能的工具,可以用来实现前面除了jstat之外所有命令的功能。比如: 用它来导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间等。

官方帮助文档:https://docs.oracle.com/en/java/javase/11/tools/jcmd.html
jcmd拥有jmap的大部分功能,并且在oracle的官方网站上也推荐使用jcmd命令代jmap命令。

8.2 Try It

列出所有的JVM进程:

jcmd -l

针对指定的进程,列出支持的所有具体命令;显示指定进程的指令命令的数据:

jcmd <进程id> help
jcmd <进程号> 具体命令

在这里插入图片描述

jcmd 22244 GC.heap_dump d:\6.hprof
jcmd 22244 VM.uptime
jcmd 22244 VM.flags

在这里插入图片描述

9 jstatd 远程主机信息收集

之前的指令只涉及到监控本机的Java应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如jps、jstat)。为了启用远程监控,则需要配合使用jstatd 工具。
命令jstatd是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。jstatd服务器将本机的Java应用程序信息传递到远程计算机。

在这里插入图片描述

10、jstack的结果集鉴赏

java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)

java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)

java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)

java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)

java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)

java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)

代码修改1

"MichaelTask-19" #63 prio=5 os_prio=0 tid=0x00007f24a0da7000 nid=0x5eaf runnable [0x00007f246cce9000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
	at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
	- locked <0x00000000902d5d78> (a java.io.BufferedInputStream)
	at sun.net.www.MeteredStream.read(MeteredStream.java:134)
	- locked <0x00000000902d5d38> (a sun.net.www.http.KeepAliveStream)
	at java.io.FilterInputStream.read(FilterInputStream.java:133)
	at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3454)
	at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3447)
	at com.michael.mytask.util.HttpUtil.readInputStream(HttpUtil.java:114)
	at com.michael.mytask.util.HttpUtil.downloadFile(HttpUtil.java:47)
	at com.michael.mytask.task.MyTask.run(MyTask.java:458)
	at sun.reflect.GeneratedMethodAccessor845.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
	at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	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)

   Locked ownable synchronizers:
	- <0x000000008e175ca8> (a java.util.concurrent.ThreadPoolExecutor$Worker)

设置ConnectTimeoutReadTimeout

URL url = new URL(urlStr);
HttpURLConnection  conn = (HttpURLConnection) url.openConnection();
if (StringUtils.isNotEmpty(yyy)) {
	conn.setRequestProperty("xxx", yyy);
}
conn.setConnectTimeout(5 * 1000);//设置连接超时时间,单位毫秒
conn.setReadTimeout(20 * 1000);//读取数据的超时时间,单位毫秒
//防止屏蔽程序抓取而返回403错误
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//得到输入流
InputStream inputStream = conn.getInputStream();

代码修改2

"Abandoned connection cleanup thread" #19 daemon prio=5 os_prio=0 tid=0x00007f24a223b000 nid=0x5e80 in Object.wait() [0x00007f24f07d4000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
	- locked <0x00000000898b8cb8> (a java.lang.ref.ReferenceQueue$Lock)
	at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:70)
	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)

   Locked ownable synchronizers:
	- <0x0000000089965a88> (a java.util.concurrent.ThreadPoolExecutor$Worker)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值