Monitor
java生产环境内存调优(包括jvm参数类型,JVM的参数类型 jinfo & jps(参数和进程查看) jstat(类加载、垃圾收集、JIT 编译) jmap+MAT(内存溢出) jstack(线程、死循环、死锁) JVisualVM(本地和远程可视化监控) 使用 BTrace 进行拦截调试 Tomcat 性能监控与调优 Nginx 性能监控与调优 JVM 层 GC 调优 JAVA代码层调优 )欢迎:star2::star2::star2::star2::star2::star2::star2::star2:
Install / Use
/learn @vipcolud/MonitorREADME
主要内容包括
| :blue_heart:|:blue_heart:|:blue_heart: |:blue_heart:|:blue_heart:|:blue_heart:| | -------- | :----: | :----: |:----: |:----: |:----: | | jvm参数类型:alien:|jinfo & jps(参数和进程查看):alien:|jstat(类加载、垃圾收集、JIT 编译):alien: |jmap+MAT(内存溢出):alien:|jstack(线程、死循环、死锁):alien:|JVisualVM(本地和远程可视化监控:alien:| |使用 BTrace进行拦截调试:alien:|Tomcat 性能监控与调优:alien:| Nginx 性能监控与调优:alien:|JVM 层 GC 调优:alien:|JAVA代码层调优:alien: |:alien:|
1.JVM的参数类型
标准参数(各版本中保持稳定)
-help
-server -client
-version -showversion
-cp -classpath
X 参数(非标准化参数)
-Xint:解释执行
-Xcomp:第一次使用就编译成本地代码
-Xmixed:混合模式,JVM 自己决定是否编译成本地代码
示例:
java -version(默认是混合模式)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
java -Xint -version
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, interpreted mode)
XX 参数(非标准化参数)
主要用于 JVM调优和 debug
Boolean类型(+-)
格式:-XX:[+-]<name>表示启用或禁用 name 属性
如:-XX:+UseConcMarkSweepGC(启用cms垃圾收集器)
-XX:+UseG1GC(启用G1垃圾收集器)
非Boolean类型(key-value)(带=的)
格式:-XX:<name>=<value>表示 name 属性的值是 value
如:-XX:MaxGCPauseMillis=500(GC最大停用时间)
-xx:GCTimeRatio=19
-Xmx -Xms属于 XX 参数
-Xms 等价于-XX:InitialHeapSize(初始化堆大小)
-Xmx 等价于-XX:MaxHeapSize (最大堆大小)
-xss 等价于-XX:ThreadStackSize(线程堆栈)
查看
jinfo -flag MaxHeapSize <pid>(查看最大内存)
-XX:+PrintFlagsInitial
-XX:+PrintFlagsFinal
-XX:+UnlockExperimentalVMOptions 解锁实验参数
-XX:+UnlockDiagnosticVMOptions 解锁诊断参数
-XX:+PrintCommandLineFlags 打印命令行参数
输出结果中=表示默认值,:=表示被用户或 JVM 修改后的值
示例:java -XX:+PrintFlagsFinal -version
2.jinfo & jps(参数和进程查看)
pid 可通过类似 ps -ef|grep tomcat或 jps来进行查看
jps
[详情参考 jps官方文档](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jps.html)
-l
jinfo
jinfo -flag MaxHeapSize <pid>
jinfo -flags <pid>
jstat
[详情参考 jps官方文档](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHBBBDJ)
jstat 使用示例
3.jstat(类加载、垃圾收集、JIT 编译)
类加载
每隔1000ms 即1秒,共输出10次
jstat -class <pid> 1000 10
loaded 加载类的个数
[root@localhost java]# jps
4167 Jps
3370 Bootstrap
[root@localhost java]# jstat -class 3370
Loaded Bytes Unloaded Bytes Time
5990 12028.7 0 0.0 15.50
垃圾收集
[root@localhost java]# jstat -gc 3370
Warning: Unresolved Symbol: sun.gc.metaspace.capacity substituted NaN
Warning: Unresolved Symbol: sun.gc.metaspace.used substituted NaN
Warning: Unresolved Symbol: sun.gc.compressedclassspace.capacity substituted NaN
Warning: Unresolved Symbol: sun.gc.compressedclassspace.used substituted NaN
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1600.0 1600.0 0.0 1600.0 13184.0 7779.2 32696.0 22669.8 - - - - 117 1.056 5 0.386 1.441
-gc, -gcutil, -gccause, -gcnew, -gcold
jstat -gc <pid> 1000 10
以下大小的单位均为 KB
S0C, S1C, S0U, S1U: S0和 S1的总量和使用量
EC, EU: Eden区总量与使用量
OC, OU: Old区总量与使用量
MC, MU: Metacspace区(jdk1.8前为 PermGen)总量与使用量
CCSC, CCSU: 压缩类区总量与使用量
YGC, YGCT: YoungGC 的次数与时间
FGC, FGCT: FullGC 的次数与时间
GCT: 总的 GC 时间
JIT 编译
-compiler, -printcompilation
[root@localhost java]# jstat -compiler 3370
Compiled Failed Invalid Time FailedType FailedMethod
833 0 0 26.04 0
花费26.04s编译了833个方法
4.jmap+MAT(内存溢出)
内存溢出演示: 生成springboot初始化代码 最终代码
为快速产生内存溢出,右击 Run As>Run Configurations, Arguments 标签VM arguments 中填入
-Xmx32M -Xms32M
访问 http://localhost:8080/heap
Exception in thread "http-nio-8080-ClientPoller-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.HashMap$KeySet.iterator(HashMap.java:916)
at java.util.HashSet.iterator(HashSet.java:172)
at java.util.Collections$UnmodifiableCollection$1.<init>(Collections.java:1039)
Exception in thread "http-nio-8080-exec-1" java.lang.OutOfMemoryError: GC overhead limit exceeded
-XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M(同时在 pom.xml 中加入 asm 的依赖)
访问 http://localhost:8080/nonheap
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
Exception in thread "ContainerBackgroundProcessor[StandardEngine[Tomcat]]" java.lang.OutOfMemoryError: Metaspace
内存溢出自动导出
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
右击 Run As>Run Configurations, Arguments 标签VM arguments 中填入
-Xmx32M -Xms32M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
可以看到自动在当前目录中生成了一个java_pid660.hprof文件
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to ./java_pid660.hprof ...
另一种导出溢出也更推荐的方式是jmap
option: -heap, -clstats, -dump:<dump-options>, -F
jmap -dump:format=b,file=heap.hprof <pid>
C:\Users\Mr Chen>jps -l
10476 sun.tools.jps.Jps
6744
14980 com.imooc.monitor_tuning.MonitorTuningApplication
C:\Users\Mr Chen>cd desktop
C:\Users\Mr Chen\Desktop>jmap -dump:format=b,file=heap.hprof 14980
Dumping heap to C:\Users\Mr Chen\Desktop\heap.hprof ...
Heap dump file created
jmap 导出溢出文件 MAT下载地址 找开上述导出的内存溢出文件即可进行分析,如下图的溢出源头分析: Memory Analyzer 内存溢出分析
5.jstack(线程、死循环、死锁)
1.线程状态
jstack: 打印jvm内部所有线程
C:\Users\Mr Chen\Desktop>jps -l
15260 com.imooc.monitor_tuning.MonitorTuningApplication
10836 sun.tools.jps.Jps
6744
C:\Users\Mr Chen\Desktop>jstack 15260> 15260.txt
可查看其中包含java.lang.Thread.State: WAITING (parking),JAVA 线程包含的状态有: NEW:线程尚未启动 RUNNABLE:线程正在 JVM 中执行 BLOCKED:线程在等待监控锁(monitor lock) WAITING:线程在等待另一个线程进行特定操作(时间不确定) TIMED_WAITING:线程等待另一个线程进行限时操作 TERMINATED:线程已退出
2.死循环导致cpu飙高
monitor_tuning中新增CpuController.java
直接 maven clean、 maven install
此时会生成一个monitor_tuning-0.0.1-SNAPSHOT.jar的 jar包,为避免本地的 CPU 消耗过多导致死机,建议上传上传到虚拟机进行测试
nohup java -jar monitor_tuning-0.0.1-SNAPSHOT.jar &
访问 http://xx.xx.xx.xx:8080/loop(端口8080在application.properties文件中定义)
top -p <pid> -H可以查看线程及 CPU 消耗情况
top 命令打出线程 CPU 消耗
使用 jstack <pid>可以导出追踪文件,文件中 PID 在 jstack 中显示的对应 nid 为十六进制(命令行可执行 print '%x' <pid>可以进行转化,如4008对应的十六进制为1007)
[root@localhost java]# jstack 4008 > 4008.txt
[root@localhost java]# printf "%x" 4103
1007[root@localhost java]# jstack 4103 > 4103.txt
"http-nio-8080-exec-7" #22 daemon prio=5 os_prio=0 tid=0x00007f6378be7000 nid=0x1026 runnable [0x00007f63556d1000]
java.lang.Thread.State: RUNNABLE
at java.lang.String.indexOf(String.java:1769)
at java.lang.String.indexOf(String.java:1718)
at com.imooc.monitor_tuning.chapter2.CpuController.getPartneridsFromJson(CpuController.java:73)
说明getPartneridsFromJson这里导致的cpu飙升
3.死锁
访问http://xx.xx.xx.xx:8080/deadlock(如上jstack <pid>导出追踪记录会发现如下这样的记录)
[root@localhost java]# ps -ef |grep java
root 4357 3145 23 02:00 pts/0 00:01:22 java -jar monitor_tuning-0.0.1-SNAPSHOT.jar
root 4474 3707 0 02:06 pts/3 00:00:00 grep --color=auto java
[root@localhost java]# jstack 4357 > 4357.txt
将文件拉到最后会发现
"Thread-5":
at com.imooc.monitor_tuning.chapter2.CpuController.lambda$deadlock$1(CpuController.java:41)
- waiting to lock <0x00000000f6b383e0> (a java.lang.Object)
- locked <0x00000000f6b383f0> (a java.lang.Object)
at com.imooc.monitor_tuning.chapter2.CpuController$$Lambda$337/678439847.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-4":
at com.imooc.monitor_tuning.chapter2.CpuController.lambda$deadlock$0(CpuController.java:33)
- waiting to lock <0x00000000f6b383f0> (a java.lang.Object)
- locked <0x00000000f6b383e0> (a java.lang.Object)
at com.imooc.monitor_tuning.chapter2.CpuController$$Lambda$336/498593401.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
线程4在等待线程5,同时线程5也在等待线程4,此时死锁
6.JVisualVM(本地和远程可视化监控)
1.监控本地java进程
详情参考官方文档 Mac命令行直接输入jvisualvm命令,Windows 找到对应的 exe 文件双击即可打开 插件安装Tools>Plugins>Settings根据自身版本(java -version)更新插件中心地址,各版本查询地址: jvisualvm插件 建议安装:Visual GC, BTrace Workbench
2.监控远程java进程
以上是本地的JAVA进程监控,还可以进行远程的监控,在上图左侧导航的 Applications 下的 Remote 处右击Add Remote Host...,输入主机 IP 即可添加,在 IP 上右击会发现有两种连接 JAVA 进程进行监控的方式:JMX, jstatd
vi bin/catalina.sh(以192.168.73.0为例)
:/JAVA_OPTS 按两个n 添加
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=192.168.73.0"
报错 异常情况:VisualVM 无法使用 service:jmx:rmi:///jndi/rmi:///jmxrmi 连接到 原因: 除了JMX server指定的监听端口号外,JMXserver还会监听一到两个随机端口号, 可以通过命grep <pid> 来查看当前java进程需要监听的随机端口号
[root@localhost bin]# jps
4216 Jps
4031 Bootstrap
[root@localhost bin]# lsof -i|grep java | grep 4031
java 4031 root 19u IPv4 32304 0t0 TCP *:33707 (LISTEN)
java 4031 root 20u IPv4 32310 0t0 TCP *:9004 (LISTEN)
java 4031 root 21u IPv4 32322 0t0 TCP *:50022 (LISTEN)
java 4031 root 53u IPv4 32323 0t0 TCP *:webcache (LISTEN)
java 4031 root 57u IPv4 32325 0t0 TCP *:8009 (LISTEN)
java 4031 root 69u IPv4 32338 0t0 TCP localhost:mxi (LISTEN)
将监听的端口去掉防火墙当然9004端口也是需要去掉的
[root@localhost bin]# iptables -I INPUT -p tcp --dport 33707 -j ACCEPT
[root@localhost bin]# iptables -I INPUT -p tcp --dport 50022 -j ACCEPT
[root@localhost bin]# iptables -I INPUT -p tcp --dport 8009 -j ACCEPT
启动tomcat,以 JMX 为例,在 IP 上右击点击Add JMX Connection...,输入 192.168.73.0:9004 Add JMX Connection 以上为 Tomcat,其它 JAVA 进程也是类似的,如:
nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9005 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=192.168.73.0 -jar monitor_tuning-0.0.1-SNAPSHOT.jar &
6.使用 BTrace 进行拦截调试
下载BTrace 可以动态地向目标应用程序的字节码注入追踪代码,使用的技术有 JavaCompilerApi, JVMTI, Agent, Instrumentation+ASM 使用方法:JVisualVM中添加 BTrace 插件 方法二:btrace <pid> <trace_script> monitor_tuning中新增包org.alanhou.monitor_tuning.chapter4 安装BTrace 要记得配置环境变量,以 windos 为例
BTRACE_
Related Skills
node-connect
341.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.5kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.5kCommit, push, and open a PR
