《深入理解Java虚拟机》3:虚拟机性能监控与故障处理工具

一、JDK的命令行工具

  • jps :虚拟机进程状况工具。 用户查看所有 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息;
  • jstat:虚拟机统计信息监视工具。用于收集 HotSpot 虚拟机各方面的运行数据;
  • jinfo:Java配置信息工具。用于显示虚拟机配置信息;
  • jmap  :Java内存映像工具。用于生成堆转储快照;
  • jhat : 虚拟机堆转储快照分析工具。用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果;
  • jstack :Java堆栈跟踪工具。用于生成虚拟机当前时刻的线程快照,线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。

1.1、jps:查看所有Java进程

类似UNIX的PS命令。

功能:显示虚拟机执行主类名称 以及 这些进程的本地虚拟机唯一ID

(1)jps -q:只输出进程的本地虚拟机唯一ID

C:\Users\SnailClimb>jps
7360 NettyClient2
17396
7972 Launcher
16504 Jps
17340 NettyServer

(2)jsp -l:输出主类全名,如果进程执行的是jar包,输出jar路径

C:\Users\SnailClimb>jps -l
7360 firstNettyDemo.NettyClient2
17396
7972 org.jetbrains.jps.cmdline.Launcher
16492 sun.tools.jps.Jps
17340 firstNettyDemo.NettyServer

(3)jps -v:输出虚拟机进程启动时 JVM 参数

(4)jps -m:输出传递给 Java 进程 main() 函数的参数

1.2、jstat:监视虚拟机各种运行状态信息

功能:用于监视虚拟机各种运行状态信息。可以显示本地或者远程虚拟机进程中的类信息、内存、垃圾收集器、JIT编译等运行数据。

命令格式:

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

 比如 jstat -gc -h3 31736 1000 10:表示分析进程 id 为 31736 的 gc 情况,每隔 1000ms 打印一次记录,打印 10 次停止,每 3 行后打印指标头部。

常见的 option 如下:

  • jstat -class vmid :显示 ClassLoader 的相关信息;
  • jstat -compiler vmid :显示 JIT 编译的相关信息;
  • jstat -gc vmid :显示与 GC 相关的堆信息;
  • jstat -gccapacity vmid :显示各个代的容量及使用情况;
  • jstat -gcnew vmid :显示新生代信息;
  • jstat -gcnewcapcacity vmid :显示新生代大小与使用情况;
  • jstat -gcold vmid :显示老年代和永久代的信息;
  • jstat -gcoldcapacity vmid :显示老年代的大小;
  • jstat -gcpermcapacity vmid :显示永久代大小;
  • jstat -gcutil vmid :显示垃圾收集信息;

注意:加上 -t参数可以在输出信息上加一个 Timestamp 列,显示程序的运行时间。

1.3、jinfo:实时地查看和调整虚拟机各项参数

(1)jinfo vmid:输出当前JVM进程的全部参数和系统属性

(2)jinfo -flag name vmid :输出对应名称的参数的具体值。比如输出MaxHeapSize(最大堆大小)、查看当前JVM进程是否开启打印GC日志( -XX:PrintGCDetails :详细 GC 日志模式)。这两个都是默认关闭的:

C:\Users\SnailClimb>jinfo  -flag MaxHeapSize 17340
-XX:MaxHeapSize=2124414976
C:\Users\SnailClimb>jinfo  -flag PrintGC 17340
-XX:-PrintGC

(3)使用jinfo可以在不重启虚拟机情况下,动态修改JVM参数。尤其在线上环境特别有用

jinfo -flag [+|-]name vmid :开启或者关闭对应名称的参数

C:\Users\SnailClimb>jinfo  -flag  PrintGC 17340
-XX:-PrintGC
C:\Users\SnailClimb>jinfo  -flag  +PrintGC 17340
C:\Users\SnailClimb>jinfo  -flag  PrintGC 17340
-XX:+PrintGC

1.4、生成堆转储快照

如果不使用jmap命令也可以使用“-XX:+HeapDumpOnOutOfMemoryError”参数获得堆转储。

作用:可以让虚拟机在OOM异常出现之后自动生成dump文件(Linux下用kill -3发出进程退出信号也能拿到dump文件);还可以查询finalizer执行队列、Java堆和永久代详细信息(空间使用率、当前使用的是哪种收集器)

示例:将指定应用程序的堆快照输出到桌面,然后可以通过 jhat、Visual VM 等工具分析该堆文件

C:\Users\SnailClimb>jmap -dump:format=b,file=C:\Users\SnailClimb\Desktop\heap.hprof 17340
Dumping heap to C:\Users\SnailClimb\Desktop\heap.hprof ...
Heap dump file created

1.5、jhat: 分析 heapdump 文件

分析1.4的那个dump文件,它会建立一个HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果

C:\Users\SnailClimb>jhat C:\Users\SnailClimb\Desktop\heap.hprof
Reading from C:\Users\SnailClimb\Desktop\heap.hprof...
Dump file created Sat May 04 12:30:31 CST 2019
Snapshot read, resolving...
Resolving 131419 objects...
Chasing references, expect 26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

访问 http://localhost:7000/

1.6、jstack :生成虚拟机当前时刻的线程快照

线程快照:当前虚拟机内每一条线程正在执行的方法堆栈的集合。

生成线程快照目的:为了定位线程长时间出现停顿的原因,如线程死锁、死循环、请求外部资源导致的长时间等待。

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

示例一个线程死锁的代码,然后通过jstack 命令进行死锁检查,输出死锁信息,找到发生死锁的线程

代码:

public class DeadLockDemo {
    private static Object resource1 = new Object();//资源 1
    private static Object resource2 = new Object();//资源 2

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 1").start();

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                }
            }
        }, "线程 2").start();
    }
}

输出:

Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1

代码分析:

线程 A 通过 synchronized (resource1) 获得 resource1 的监视器锁,然后通过 Thread.sleep(1000);让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。

通过 jstack 命令分析:

C:\Users\SnailClimb>jps
13792 KotlinCompileDaemon
7360 NettyClient2
17396
7972 Launcher
8932 Launcher
9256 DeadLockDemo
10764 Jps
17340 NettyServer

C:\Users\SnailClimb>jstack 9256

输出的部分内容如下,可以看到 jstack 命令已经帮找到发生死锁的线程的具体信息:

Found one Java-level deadlock:
=============================
"线程 2":
  waiting to lock monitor 0x000000000333e668 (object 0x00000000d5efe1c0, a java.lang.Object),
  which is held by "线程 1"
"线程 1":
  waiting to lock monitor 0x000000000333be88 (object 0x00000000d5efe1d0, a java.lang.Object),
  which is held by "线程 2"

Java stack information for the threads listed above:
===================================================
"线程 2":
        at DeadLockDemo.lambda$main$1(DeadLockDemo.java:31)
        - waiting to lock <0x00000000d5efe1c0> (a java.lang.Object)
        - locked <0x00000000d5efe1d0> (a java.lang.Object)
        at DeadLockDemo$$Lambda$2/1078694789.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)
"线程 1":
        at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16)
        - waiting to lock <0x00000000d5efe1d0> (a java.lang.Object)
        - locked <0x00000000d5efe1c0> (a java.lang.Object)
        at DeadLockDemo$$Lambda$1/1324119927.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

二、JDK的可视化工具

2.1、JConsole:Java监视与管理控制台

工具简介:JConsole 是基于JMX的可视化检测、管理工具。可以很方便地检测本地以及远程服务器的Java进程的内存使用情况。可以在控制台输出console命令启动或者在JDK目录下的bin目录找到jconsole.exe然后双击启动。

(1)连接JConsole:

连接 Jconsole

如果需要使用 JConsole 连接远程进程,可以在远程 Java 程序启动时加上下面这些参数:

-Djava.rmi.server.hostname=外网访问 ip 地址 
-Dcom.sun.management.jmxremote.port=60001   //监控的端口号
-Dcom.sun.management.jmxremote.authenticate=false   //关闭认证
-Dcom.sun.management.jmxremote.ssl=false

在使用 JConsole 连接时,远程进程地址如下:

外网访问 ip 地址:60001 

(2)查看 Java 程序概况:

查看 Java 程序概况

(3)内存监控

JConsole可以显示当前内存的详细信息。包括堆内存/非堆内存的完整信息,还可以细化到eden区、survivor区的使用情况。

如图,点击右上角的“执行 GC(G)”按钮可以强制应用程序执行一个 Full GC。

  • 新生代 GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC 非常频繁,回收速度一般也比较快。
  • 老年代 GC(Major GC/Full GC):指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上

内存监控

(4)线程监管

前面讲的 jstack 命令,不过这个是可视化的。

如图,点击最下面有一个"检测死锁 (D)"按钮,点击这个按钮可以自动为你找到发生死锁的线程以及它们的详细信息 。

线程监控

2.2、Visual VM:多合一故障处理工具(强大)

VisualVM简介:提供图形界面,在Java虚拟机上运行的Java应用程序的详细信息。是最强大的运行监视和故障处理程序。

VisualVM优点:免费、不需要被监视的程序基于特殊Agent运行,对其他程序性能影响小,可直接应用在生产环境中

 

VisualVM作用:运行监视和故障处理、性能分析( JProfiler、YourKit收费的,它免费):

  • 显示虚拟机进程、进程的配置、环境信息(jps、jinfo);
  • 监视应用程序的CPU、GC、堆、方法区、线程的信息(jstat、jstack);
  • dump、分析堆转储快照(jmap、jhat);
  • 方法级的程序运行性能分析、可找到被调用最多和运行时间最长的方法;
  • 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可将快照发送开发者处进行Bug反馈。

三、Tomcat配置调优测试

3.1、Jmeter压力测试工具(真正压力测试是在Linux测试的)

JMeter简介:是一款开源性能测试工具,类似LoadRunner ,它也提供了一个利用本地Proxy Server(代理服务器)来录制生成测试脚本的功能(不常用)、使用Badboy录制生成 JMeter脚本(常用)。

Badboy简介:Badboy是一款不错的Web自动化测试工具,Badboy提供了将Web测试脚本直接导出生成JMeter脚本的功能。

Badboy使用步骤:

  • 1.      通过Badboy的官方网站下载Badboy的最新版本;
  • 2.      安装Badboy。安装过程同一般的Windows 应用程序没有什么区别,安装完成后你可以在桌面和Windows开始菜单中看到相应的快捷方式——如果找不到,可以找一下Badboy安装目录下的Badboy.exe 文件,直接双击启动Badboy;
  • 3.      启动Badboy,以看到下面的界面:
  • 在地址栏(图中红色方框标注的部分)中输入你需要录制的Web应用的URL——这里我们以http://www.yahoo.com 为例,并点击GO 按钮开始录制。
  • 4.      开始录制后,你可以直接在Badboy内嵌的浏览器(主界面的右侧)中对被测应用进行操作,所有的操作都会被记录在主界面左侧的编辑窗口中——在这个试验中,我们在Yahoo的搜索引擎中输入 JMeter 进行搜索。不过你将看到,录制下来的脚本并不是一行行的代码,而是一个个Web对象——这就有点像LoadRunner的VuGen中的Tree View视图;
  • 5.      录制完成后,点击工具栏中的“停止录制”按钮,完成脚本的录制;
  • 6.      选择“File -> Export to JMeter”菜单,填写文件名“login_mantis.jmx”,将录制好脚本导出为JMeter脚本格式。也可以选择“File -> Save”菜单保存为Badboy脚本;
  • 7.      启动JMeter并打开刚刚生成的测试脚本。
     

3.2、什么是吞吐量 / JVM简单调参调优

就是“每秒查询率”,是一台服务器每秒能够响应的查询次数,是对一个特定查询服务规定时间内所处理流量的多少的衡量标准。

(1)测试串行吞吐量:

初始化测试:

-XX:+PrintGCDetails -Xmx32M -Xms1M  

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseSerialGC

-XX:PermSize=32M

GC 回收次数25次 吞吐量4662

加大初始堆内存大小-Xms1M 修改为32m

GC 回收次数7次 吞吐量5144

结论

堆的 初始值和堆的最大值 一致(可提高吞吐量)

扩大堆内存:

-XX:+PrintGCDetails -Xmx512M -Xms32M

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseSerialGC

-XX:PermSize=32M

堆内存扩大为512M

GC 回收次数6次(差不多不变) 吞吐量5141(差不多不变)

结论:

垃圾回收次数 和设置最大堆内存大小无关,只和 堆初始值 有关系。

初始内存会影响吞吐量。

 

调整初始堆:

-XX:+PrintGCDetails -Xmx512M –Xms512M

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseSerialGC

-XX:PermSize=32M

GC回收次数0次(没有GC回收,因为初始堆值够大) 吞吐量6561次

结论

堆的初始值和最大堆内存一致,并且初始堆越大就会高

(2)并行回收(UseParNewGC):

例子还是串行回收的例子

-XX:+PrintGCDetails -Xmx512M -Xms512M

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseParNewGC

-XX:PermSize=32M

GC回收0次 吞吐量6800(吞吐量高了)

CMS收集器:

-XX:+PrintGCDetails -Xmx512M -Xms512M

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseConcMarkSweepGC

-XX:PermSize=32M

 

G1回收方式:

-XX:+PrintGCDetails -Xmx512M -Xms512M

-XX:+HeapDumpOnOutOfMemoryError

-XX:+UseG1GC

-XX:PermSize=32M

 

3.3、JVM调优总结

(1)减少GC对老年代的回收,减少GC回收次数;

(2)堆初始值和最大值一致

(3)初始堆值和最大堆内存越大,吞吐量越高

(4)最好使用并行收集器,因为并行收集器比串行收集器吞吐量高、速度快(但效率不一定比串行高)

(5)设置堆内存新生代的比例和老年代的比例最好是 1:2 或者 1:3

 

四、垃圾回收策略

4.1、Minor GC和Full GC区别

新生代 GC(Minor GC)

指发生在新生代的垃圾回收,以为Java对象大多具有死亡快的特性,所以新生代回收很频繁,回收速度也快;

 老年代 GC(Major GC  / Full GC)

指发生在老年代的 GC,出现了Major GC一般会伴随至少一次Minor GC(why?),MajorGC 的速度一般会比 Minor GC 慢 10倍以上;

Minor GC触发机制:当新生代满时就会触发Minor  GC,这里的新生代满指的是Eden区代满,Survivor区满不会引发GC

Full GC触发机制:当老年代满时会触发Full GC,Full GC会同时回收新生代、老年代(一锅端),JDK1.7以前当永久代满时也会触发Full GC。

4.2、JVM的永久代中会发生垃圾回收么?

垃圾回收不会发生在永久代,如果永久代满了或者超过了临界值会触发完全垃圾回收Full GC(这TM为啥不算触发垃圾回收?)


### 若对你有帮助的话,欢迎点赞!评论!转发!谢谢!

上一篇:垃圾收集器与内存分配策略

下一篇:调优案例分析与实战

  参考资料:深入理解Java虚拟机(第2版) : JVM高级特性与最佳实

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园信息化系统解决方案旨在通过先进的信息技术,实现教育的全方位创新和优质资源的普及共享。该方案依据国家和地方政策背景,如教育部《教育信息化“十三五”规划》和《教育信息化十年发展规划》,以信息技术的革命性影响为指导,推进教育信息化建设,实现教育思想和方法的创新。 技术发展为智慧校园建设提供了强有力的支撑。方案涵盖了互连互通、优质资源共享、宽带网络、移动APP、电子书包、电子教学白板、3D打印、VR虚拟教学等技术应用,以及大数据和云计算技术,提升了教学数据记录和分析水平。此外,教育资源公共服务平台、教育管理公共服务平台等平台建设,进一步提高了教学、管控的效率。 智慧校园系统由智慧教学、智慧管控和智慧办公三大部分组成,各自具有丰富的应用场景。智慧教学包括微课、公开课、精品课等教学资源的整合和共享,支持在线编辑、录播资源、教学分析等功能。智慧管控则通过平安校园、可视对讲、紧急求助、视频监控等手段,保障校园安全。智慧办公则利用远程视讯、无纸化会议、数字会议等技术,提高行政效率和会议质量。 教育录播系统作为智慧校园的重要组成部分,提供了一套满足学校和教育局需求的解决方案。它包括标准课室、微格课室、精品课室等,通过自动五机位方案、高保真音频采集、一键式录课等功能,实现了优质教学资源的录制和共享。此外,录播系统还包括互动教学、录播班班通、教育中控、校园广播等应用,促进了教育资源的均衡化发展。 智慧办公的另一重点是无纸化会议和数字会议系统的建设,它们通过高效的文件管理、会议文件保密处理、本地会议的音频传输和摄像跟踪等功能,实现了会议的高效化和集中管控。这些系统不仅提高了会议的效率和质量,还通过一键管控、无线管控等设计,简化了操作流程,使得会议更加便捷和环保。 总之,智慧校园信息化系统解决方案通过整合先进的信息技术和教学资源,不仅提升了教育质量和管理效率,还为实现教育均衡化和资源共享提供了有力支持,推动了教育现代化的进程。
智慧校园信息化系统解决方案旨在通过先进的信息技术,实现教育的全方位创新和优质资源的普及共享。该方案依据国家和地方政策背景,如教育部《教育信息化“十三五”规划》和《教育信息化十年发展规划》,以信息技术的革命性影响为指导,推进教育信息化建设,实现教育思想和方法的创新。 技术发展为智慧校园建设提供了强有力的支撑。方案涵盖了互连互通、优质资源共享、宽带网络、移动APP、电子书包、电子教学白板、3D打印、VR虚拟教学等技术应用,以及大数据和云计算技术,提升了教学数据记录和分析水平。此外,教育资源公共服务平台、教育管理公共服务平台等平台建设,进一步提高了教学、管控的效率。 智慧校园系统由智慧教学、智慧管控和智慧办公三大部分组成,各自具有丰富的应用场景。智慧教学包括微课、公开课、精品课等教学资源的整合和共享,支持在线编辑、录播资源、教学分析等功能。智慧管控则通过平安校园、可视对讲、紧急求助、视频监控等手段,保障校园安全。智慧办公则利用远程视讯、无纸化会议、数字会议等技术,提高行政效率和会议质量。 教育录播系统作为智慧校园的重要组成部分,提供了一套满足学校和教育局需求的解决方案。它包括标准课室、微格课室、精品课室等,通过自动五机位方案、高保真音频采集、一键式录课等功能,实现了优质教学资源的录制和共享。此外,录播系统还包括互动教学、录播班班通、教育中控、校园广播等应用,促进了教育资源的均衡化发展。 智慧办公的另一重点是无纸化会议和数字会议系统的建设,它们通过高效的文件管理、会议文件保密处理、本地会议的音频传输和摄像跟踪等功能,实现了会议的高效化和集中管控。这些系统不仅提高了会议的效率和质量,还通过一键管控、无线管控等设计,简化了操作流程,使得会议更加便捷和环保。 总之,智慧校园信息化系统解决方案通过整合先进的信息技术和教学资源,不仅提升了教育质量和管理效率,还为实现教育均衡化和资源共享提供了有力支持,推动了教育现代化的进程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值