首先我们需要知道 java 的进程 id :
jps
➔ jps
38474 Application
53679 Jps
6511
可以看到应用 Application 对应的进程 id 为 38474
如果想查看完整的包名可以加上参数 -l
, 如
jps -l
60740 sun.tools.jps.Jps
53913 org.jetbrains.jps.cmdline.Launcher
38474 com.robert.vesta.rest.Application
6511
还可以通过参数 -m
查看传入 main 函数的参数,也可以 -v
查看 jvm 参数;更详细的参数说明可以通过 man jps
查看。
查看 jvm 参数
jcmd 38474 VM.flags
或 jinfo -flags 38474
jmap 查看内存对象信息和堆信息
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jmap.html
在我们发现线上服务器内存紧张的时候,如果花时间分析问题、然后改代码、测试、再上线,可能已经由于资源不足严重影响到线上服务了;这时候只能先来个“万灵药 - 重启大法”,但是后续还是要分析问题的,这时候就可以利用 jmap 来将当时的内存信息给 dump 下来;
如 jmap -dump:[live,]format=b,file=
, :live 表示只 dump 存活对象
查看堆的概要信息和 gc 各代的情况 jmap -heap {pid}
jmap -heap 38474
Attaching to process ID 38474, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 44564480 (42.5MB)
MaxNewSize = 715653120 (682.5MB)
OldSize = 89653248 (85.5MB)
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 = 256901120 (245.0MB)
used = 1804240 (1.7206573486328125MB)
free = 255096880 (243.2793426513672MB)
0.7023091218909439% used
From Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
To Space:
capacity = 12058624 (11.5MB)
used = 0 (0.0MB)
free = 12058624 (11.5MB)
0.0% used
PS Old Generation
capacity = 72876032 (69.5MB)
used = 16337096 (15.580268859863281MB)
free = 56538936 (53.91973114013672MB)
22.417653035774507% used
15144 interned Strings occupying 2025832 bytes.
jvm 运行时信息观测工具 jstat
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html
jstat -options
-class // 显示 ClassLoader 的相关信息
-compiler // 显示 JIT 编译信息
-gc // 显示 gc 相关信息
-gccapacity // 显示gc 各代容量和使用情况
-gccause // 显示gc相关信息,并显示最后一次或当前正发生gc的诱因
-gcmetacapacity // 元数据区容量
-gcnew // 新生代信息
-gcnewcapacity // 新生代大小
-gcold // 老年代和永久代信息
-gcoldcapacity // 老年代的大小
-gcutil // 显示垃圾收集信息
-printcompilation
可以看到 jstat 功能还是很强大的, 基本的命令格式是 jstat [ generalOption | outputOptions vmid [ interval[s|ms] [ count ] ]
举个常用的例子,如果我们想实时查看 gc 的过程,可以利用 jstat -gcutil {pid} 1s 100
来隔一秒打印一次gc信息,总共打印 100次,后面的100也可以省略,表示次数不限
jstat -gcutil 38474 1s 100
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
0.00 0.00 0.95 22.42 95.94 92.55 16 0.949 4 0.682 1.631
...
jinfo 查看 java 进程的属性,也可以运行时修改部分参数
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jinfo.html
查看单个 jvm 参数 jinfo -flag {param} {pid}
➔ jinfo -flag NewSize 38474
-XX:NewSize=44564480
查看所有,加个复数 jinfo -flags {pid}
➔ jinfo -flags 38474
Attaching to process ID 38474, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13
Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:CICompilerCount=3 -XX:+FlightRecorder -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:MaxNewSize=715653120 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:+PrintGCDetails -XX:TieredStopAtLevel=1 -XX:+UnlockCommercialFeatures -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
Command line: -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:50533,suspend=y,server=n -Dvisualvm.id=239594115575912 -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dfile.encoding=UTF-8
jstack 线程堆栈
通过打印线程堆栈,可以很容易发现死锁
jstack [-l] {pid}
或 jcmd {pid} Thread.print
多功能的 jcmd
jdk8 之后的 jcmd 是综合诊断命令,可以用它直接查看 VM 基本信息,触发 GC , dump 堆等;可以部分替代 jstack、jmap、jinfo
直接敲 jcmd
也可以像 jps -l
一样找到 java 进程
➔ jcmd
53913 org.jetbrains.jps.cmdline.Launcher /Applications/IntelliJ IDEA.app/Contents/lib/lz4-java-...
38474 com.robert.vesta.rest.Application
6511
62127 sun.tools.jcmd.JCmd
jcmd {pid} help
查看支持的命令选项
➔ jcmd 38474 help
38474:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print // 打印线程信息,jstack {pid}
GC.class_stats
GC.class_histogram
GC.heap_dump // dump堆 jcmd {pid} GC.head_dump -all FILE_WITH_PATH, 等同同 jmap -dump:format=b,file=FILE_WITH_PATH
GC.run_finalization
GC.run // 触发 gc
VM.uptime // jvm以启动时间
VM.flags // 查看生效的 jvm 调优标示,同 jinfo -flags {pid}
VM.system_properties // 查看系统属性(包括 -Dxx, 动态添加的属性和jvm默认属性), 同 jinfo -sysprops {pid}
VM.command_line
VM.version // jvm 版本
help
jcmd 的命令选项区分还是很清晰的,垃圾回收的直接以 GC 开头,jvm 相关的直接以 VM 开头;如果需要查看 jcmd 选项的具体用法 可以继续 jcmd {pid} help {option}
如,
➔ jcmd 23223 help GC.heap_dump
23223:
GC.heap_dump
Generate a HPROF format dump of the Java heap.
Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified.
Permission: java.lang.management.ManagementPermission(monitor)
Syntax : GC.heap_dump [options]
Arguments:
filename : Name of the dump file (STRING, no default value)
Options: (options must be specified using the or = syntax)
-all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)