一、调优命令
Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo 。
1.1、jps
JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
1.2、jstat
JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
1、基本语法:
# 基本格式
jstat -<option> <vmid> [interval] [count]
# 常用示例
jstat -gc 1234 1000 10 # 每秒输出进程号1234的GC信息,共输出10次
2、查看类加载统计:
# 查看类加载信息
jstat -class <pid>
# 输出示例:
Loaded Bytes Unloaded Bytes Time
7035 14506 0 0 3.67
# 字段说明:
Loaded : 加载class的数量
Bytes : 加载class的字节数
Unloaded : 未加载class的数量
Bytes : 未加载class的字节数
Time : 加载时间
3、查看GC统计:
# 查看GC统计信息
jstat -gc <pid>
# 输出示例:
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 8171.9 20480.0 20480.0 4864.0 3720.0 512.0 324.8 2 0.002 1 0.003 0.005
# 字段说明:
S0C: Survivor0区容量
S1C: Survivor1区容量
S0U: Survivor0区已使用
S1U: Survivor1区已使用
EC : Eden区容量
EU : Eden区已使用
OC : 老年代容量
OU : 老年代已使用
MC : 方法区容量
MU : 方法区已使用
YGC: 年轻代GC次数
YGCT: 年轻代GC时间
FGC: Full GC次数
FGCT: Full GC时间
GCT: 总GC时间
4、查看GC详细信息:
# 查看新生代GC统计
jstat -gcnew <pid>
# 输出示例:
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
1024.0 1024.0 0.0 1024.0 1 15 1024.0 8192.0 7623.5 2 0.002
# 字段说明:
TT : Tenuring threshold(晋升阈值)
MTT : Maximum tenuring threshold(最大晋升阈值)
DSS : Desired survivor size(期望的survivor大小)
实际使用示例:
# 监控内存使用情况
while true; do
# 每5秒输出一次GC信息
jstat -gc $(jps | grep MyApp | awk '{print $1}') 5000
done
# 输出到文件进行分析
jstat -gc $(jps | grep MyApp | awk '{print $1}') 1000 > gc.log
5、性能分析脚本:
#!/bin/bash
# gc_monitor.sh
PID=$1
INTERVAL=${2:-1000} # 默认1000ms
COUNT=${3:-""} # 默认持续输出
if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [interval] [count]"
exit 1
fi
# 输出表头
echo "Time YGC YGCT FGC FGCT GCT"
# 监控GC情况
jstat -gc $PID $INTERVAL $COUNT | awk '
NR>1 {
printf "%s %d %.3f %d %.3f %.3f\n",
strftime("%H:%M:%S"),
$15, # YGC
$16, # YGCT
$17, # FGC
$18, # FGCT
$19 # GCT
}'
6、内存分析脚本:
#!/bin/bash
# memory_monitor.sh
PID=$1
INTERVAL=${2:-1000}
COUNT=${3:-""}
if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [interval] [count]"
exit 1
fi
# 输出表头
echo "Time Eden% Old% Meta%"
# 监控内存使用率
jstat -gc $PID $INTERVAL $COUNT | awk '
NR>1 {
eden_used=$6
eden_capacity=$5
old_used=$8
old_capacity=$7
meta_used=$10
meta_capacity=$9
printf "%s %.1f%% %.1f%% %.1f%%\n",
strftime("%H:%M:%S"),
eden_used/eden_capacity*100,
old_used/old_capacity*100,
meta_used/meta_capacity*100
}'
7、常见用法:
# 1. 查看类加载情况
jstat -class $(jps | grep MyApp | awk '{print $1}')
# 2. 查看GC情况
jstat -gc $(jps | grep MyApp | awk '{print $1}')
# 3. 查看JIT编译情况
jstat -compiler $(jps | grep MyApp | awk '{print $1}')
# 4. 持续监控
jstat -gcutil $(jps | grep MyApp | awk '{print $1}') 1000
# 5. 输出到文件
jstat -gc $(jps | grep MyApp | awk '{print $1}') 1000 > gc.log
1.3、jmap
1、基本语法:
# 基本格式
jmap [options] <pid>
# 常用选项
-heap # 显示堆内存信息
-histo # 显示对象统计信息
-dump # 生成堆转储文件
查看堆内存信息:
# 查看堆内存概况
jmap -heap <pid>
# 输出示例:
Attaching to process ID 1234, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 715653120 (682.5MB)
MaxNewSize = 715653120 (682.5MB)
OldSize = 1431830528 (1365.5MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.8MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 679477248 (648.0MB)
used = 424089480 (404.44MB)
free = 255387768 (243.56MB)
62.41% used
From Space:
capacity = 18087936 (17.25MB)
used = 0 (0.0MB)
free = 18087936 (17.25MB)
0.0% used
To Space:
capacity = 18087936 (17.25MB)
used = 0 (0.0MB)
free = 18087936 (17.25MB)
0.0% used
PS Old Generation
capacity = 1431830528 (1365.5MB)
used = 474547616 (452.56MB)
free = 957282912 (912.94MB)
33.14% used
2、生成堆转储文件:
# 生成堆转储文件
jmap -dump:format=b,file=heap.hprof <pid>
# 在发生OOM时自动生成堆转储文件
jmap -dump:live,format=b,file=heap.hprof <pid>
# 使用示例:
public class HeapDumpDemo {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // 1MB
Thread.sleep(100);
}
}
}
3、查看对象统计信息:
# 显示堆中对象统计信息
jmap -histo <pid>
# 只显示存活对象
jmap -histo:live <pid>
# 输出示例:
num #instances #bytes class name
----------------------------------------------
1: 500000 20000000 java.lang.String
2: 30000 15000000 byte[]
3: 1000 800000 java.lang.Class
4、实际应用脚本:
#!/bin/bash
# heap_monitor.sh
PID=$1
DUMP_PATH=${2:-"./dumps"}
INTERVAL=${3:-3600} # 默认每小时
if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [dump_path] [interval]"
exit 1
fi
mkdir -p $DUMP_PATH
while true; do
DATE=$(date +%Y%m%d_%H%M%S)
DUMP_FILE="$DUMP_PATH/heap_$DATE.hprof"
# 生成堆转储文件
jmap -dump:live,format=b,file=$DUMP_FILE $PID
# 生成对象统计信息
jmap -histo:live $PID > "$DUMP_PATH/histo_$DATE.txt"
sleep $INTERVAL
done
5、内存泄漏分析:
#!/bin/bash
# leak_analyzer.sh
PID=$1
THRESHOLD=${2:-90} # 默认内存使用率阈值
if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [threshold]"
exit 1
fi
while true; do
# 获取堆使用率
HEAP_USAGE=$(jmap -heap $PID | grep "used" | awk '{sum+=$3} END {print sum/1024/1024}')
if [ $(echo "$HEAP_USAGE > $THRESHOLD" | bc) -eq 1 ]; then
echo "Memory usage above threshold: $HEAP_USAGE MB"
DUMP_FILE="heap_$(date +%Y%m%d_%H%M%S).hprof"
jmap -dump:live,format=b,file=$DUMP_FILE $PID
fi
sleep 60
done
6、常见问题分析:
# 1. 查看最大的对象
jmap -histo:live <pid> | sort -k 3 -n -r | head -n 20
# 2. 检查字符串常量池
jmap -clstats <pid>
# 3. 分析内存泄漏
jmap -dump:live,format=b,file=leak.hprof <pid>
# 4. 查看类加载情况
jmap -clstats <pid>
7、性能优化建议:
# 1. 定期监控
0 * * * * /path/to/heap_monitor.sh <pid>
# 2. 设置告警
if [ $(jmap -heap <pid> | grep "used" | awk '{print $3}') -gt 1000000000 ]; then
echo "High memory usage alert!"
fi
# 3. 自动清理旧转储文件
find /path/to/dumps -name "heap_*.hprof" -mtime +7 -delete
1.4、jhat
jhat 是一个用于分析 Java 堆转储文件的工具。它可以帮助开发者查看和分析 Java 应用程序的内存使用情况。
1、基本语法:
jhat [options] <heap_dump_file>
2、生成堆转储文件:
在使用 jhat 之前,首先需要生成一个堆转储文件。可以使用 jmap 或 jcmd 命令来生成堆转储文件。
# 使用 jmap 生成堆转储文件
jmap -dump:live,format=b,file=heap_dump.hprof <pid>
# 或者使用 jcmd
jcmd <pid> GC.heap_dump filename=heap_dump.hprof
3、使用 jhat 分析堆转储文件:
# 启动 jhat 分析堆转储文件
jhat heap_dump.hprof
4、jhat 启动后的输出:
当你运行 jhat 后,它会启动一个 HTTP 服务器,通常在 http://localhost:7000
上。你可以在浏览器中访问这个地址来查看分析结果。
5、jhat 的常用选项:
-J<flag>: 传递参数给 JVM。例如,-J-Xmx512m 可以设置最大堆大小。
-port <port>: 指定 jhat 服务器的端口,默认是 7000。
-h 或 --help: 显示帮助信息。
6、示例:
# 生成堆转储文件
jmap -dump:live,format=b,file=heap_dump.hprof <pid>
# 使用 jhat 分析堆转储文件
jhat heap_dump.hprof
# 访问分析结果
# 打开浏览器,访问 http://localhost:7000
7、分析结果:
在浏览器中,你将看到以下信息:
- Classes: 显示堆中所有类的实例数量和占用内存。
- Instances: 显示每个类的实例详细信息。
- Paths: 显示从根对象到特定对象的路径,帮助分析内存泄漏。
8、使用 jhat 的注意事项:
性能: jhat 在处理大型堆转储文件时可能会消耗大量内存和时间。
过时: jhat 在某些情况下可能不再是最佳选择,考虑使用更现代的工具,如 Eclipse Memory Analyzer (MAT) 或 VisualVM。
9、现代替代方案:
Eclipse Memory Analyzer (MAT): 提供更强大的分析功能和图形界面。
VisualVM: 也可以分析堆转储文件,并提供实时监控功能。
1.5、jstack
jstack 是一个用于生成 Java 线程堆栈跟踪的工具,通常用于分析 Java 应用程序的线程状态和死锁情况。
1、基本语法:
jstack [options] <pid>
2、查看线程堆栈:
# 查看指定进程的线程堆栈
jstack <pid>
3、示例:
假设你有一个 Java 应用程序正在运行,进程 ID 为 12345,你可以使用以下命令查看线程堆栈:
jstack 12345
4、输出示例:
jstack 的输出将显示所有线程的状态,包括线程名称、状态、锁信息等。例如:
"main" #1 prio=5 os_prio=0 tid=0x00007f8c4c001800 nid=0x1b03 waiting for monitor entry [0x00007f8c4c7f2000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting to lock <0x00000000f8c4c8b0> (a java.lang.Object)
at java.lang.Object.wait(Object.java:502)
at java.lang.Thread.join(Thread.java:1252)
at com.example.MyClass.main(MyClass.java:10)
5、生成线程转储文件
如果想将线程堆栈输出保存到文件中,可以使用重定向:
jstack 12345 > thread_dump.txt
6、检查死锁
jstack 还可以帮助你检查死锁情况。你可以在输出中查找 Found one Java-level deadlock 的信息。
# 检查死锁
jstack -l <pid>
1.6、jinfo
jinfo 是一个用于获取和修改 Java 进程的配置信息的工具。它可以帮助开发者查看 JVM 参数、系统属性以及其他运行时信息。
1、基本语法:
# 基本格式
jinfo [option] <pid>
# 常用选项
-flag <name> # 打印指定名称的参数
-flag [+|-]<name> # 启用/禁用指定名称的参数
-flag <name>=<value> # 设置指定参数的值
-flags # 打印所有参数
-sysprops # 打印系统属性
2、查看 JVM 参数:
# 查看所有 JVM 参数
jinfo -flags <pid>
# 查看特定参数
jinfo -flag MaxHeapSize <pid>
jinfo -flag UseG1GC <pid>
# 输出示例:
-XX:MaxHeapSize=2147483648
-XX:+UseG1GC
3、查看系统属性:
# 查看所有系统属性
jinfo -sysprops <pid>
# 输出示例:
java.runtime.name=Java(TM) SE Runtime Environment
java.vm.version=25.271-b09
java.home=/path/to/java
user.dir=/path/to/working/directory
4、修改运行时参数:
你可以使用 -flag 选项来修改 JVM 参数。例如,修改最大堆大小:
# 启用/禁用布尔类型参数
jinfo -flag +PrintGC <pid> # 启用GC日志打印
jinfo -flag -PrintGC <pid> # 禁用GC日志打印
# 设置数值类型参数
jinfo -flag MaxHeapSize=2147483648 <pid>
5、实际应用示例:
public class JInfoDemo {
public static void main(String[] args) throws Exception {
// 打印进程ID
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
System.out.println("Process ID: " + pid);
// 保持程序运行
Thread.sleep(Integer.MAX_VALUE);
}
}
6、监控脚本:
#!/bin/bash
# jvm_monitor.sh
PID=$1
INTERVAL=${2:-60} # 默认60秒
if [ -z "$PID" ]; then
echo "Usage: $0 <pid> [interval]"
exit 1
fi
while true; do
echo "=== $(date) ==="
# 打印堆内存使用情况
jinfo -flag MaxHeapSize $PID
jinfo -flag HeapSize $PID
# 打印GC相关参数
jinfo -flag UseG1GC $PID
jinfo -flag UseParallelGC $PID
sleep $INTERVAL
done
7、参数检查脚本:
#!/bin/bash
# check_params.sh
PID=$1
PARAM_FILE="jvm_params.txt"
if [ -z "$PID" ]; then
echo "Usage: $0 <pid>"
exit 1
fi
# 保存当前参数
jinfo -flags $PID > $PARAM_FILE
# 检查关键参数
echo "Checking critical parameters..."
# 检查堆大小
MAX_HEAP=$(grep "MaxHeapSize" $PARAM_FILE | awk '{print $2}')
if [ $MAX_HEAP -lt 2147483648 ]; then # 2GB
echo "Warning: MaxHeapSize is less than 2GB"
fi
# 检查GC参数
if ! grep -q "UseG1GC" $PARAM_FILE; then
echo "Warning: G1GC is not enabled"
fi
8、常见用法:
# 1. 查看基本信息
jinfo <pid>
# 2. 查看所有标志
jinfo -flags <pid>
# 3. 查看特定标志
jinfo -flag UseG1GC <pid>
# 4. 修改标志
jinfo -flag +PrintGC <pid>
# 5. 查看系统属性
jinfo -sysprops <pid>
二、调优工具
常用调优工具分为两类,jdk 自带监控工具:jconsole 和 jvisualvm,第三方有:MAT (Memory Analyzer Tool)、GChisto。
1、jconsole,Java Monitoring and Management Console 是从 java5 开始,在 JDK 中自带的 java 监控和管理控制台,用于对 JVM 中内存,线程和类等的监控
2、jvisualvm,jdk 自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC 变化等。
3、MAT,Memory Analyzer Tool,一个基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Javaheap 分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。
4、GChisto,一款专业分析 gc 日志的工具
评论