JVM 自带命令系统指南
1. 基础开发工具
1.1 编译和运行
# javac - Java 编译器
javac [options] sourcefiles
# 常用选项:
javac -cp classpath -d outputdir *.java
javac -encoding UTF-8 -sourcepath src -d build src/**/*.java
# java - Java 运行时
java [options] class [args...]
java [options] -jar jarfile [args...]
# 常用选项:
java -cp classpath -Xmx2g -Xms1g com.example.Main
java -Dfile.encoding=UTF-8 -Dspring.profiles.active=prod -jar app.jar
1.2 打包和管理
# jar - JAR 文件管理
jar [options] jarfile [manifest] files...
# 常用操作:
jar -cvf app.jar -C build . # 创建 JAR
jar -xvf app.jar # 解压 JAR
jar -tf app.jar # 列出内容
jar -uvf app.jar newfile.class # 更新 JAR
1.3 反编译和文档
# javap - 类文件反汇编
javap [options] classes
# 常用选项:
javap -c ClassName # 显示字节码
javap -v ClassName # 详细信息
javap -s ClassName # 显示内部类型签名
javap -private ClassName # 显示私有成员
# javadoc - 文档生成
javadoc [options] packagenames sourcefiles
# 常用选项:
javadoc -d docs -sourcepath src -subpackages com.example
javadoc -encoding UTF-8 -charset UTF-8 -windowtitle "API Doc" src/**/*.java
# 实战场景: 当遇到 NoSuchMethodError 时,可以使用 javap 检查类的方法签名是否正确
2. 进程和系统信息
2.1 进程管理
# jps - Java 进程状态
jps [options] [hostid]
# 选项说明:
jps # 显示进程 ID 和主类名
jps -l # 显示完整类名或 JAR 路径
jps -v # 显示 JVM 参数
jps -m # 显示 main 方法参数
jps -q # 只显示进程 ID
jps -lvm # 组合使用多个选项
# 示例:
jps -lv | grep MyApp # 查找特定应用
jps -q | wc -l # 统计 Java 进程数量
2.2 系统信息查看
# jinfo - 配置信息
jinfo [options] pid
# 常用操作:
jinfo pid # 显示所有系统属性和 JVM 参数
jinfo -flags pid # 显示 JVM 命令行参数
jinfo -sysprops pid # 显示系统属性
jinfo -flag PrintGCDetails pid # 查看特定参数值
jinfo -flag +PrintGCDetails pid # 动态开启参数
jinfo -flag -PrintGCDetails pid # 动态关闭参数
3. 内存监控和分析
3.1 内存统计
# jstat - 统计信息
jstat [options] vmid [interval] [count]
# 垃圾收集统计
jstat -gc pid # 显示 GC 信息
jstat -gc pid 1s 10 # 每秒显示一次,共 10 次
jstat -gcutil pid 5s # 显示 GC 利用率
jstat -gccapacity pid # 显示堆容量信息
jstat -gcnew pid # 新生代统计
jstat -gcold pid # 老年代统计
# 堆信息
jstat -gccapacity pid # 堆容量统计
jstat -gcnewcapacity pid # 新生代容量
jstat -gcoldcapacity pid # 老年代容量
# 类加载统计
jstat -class pid # 类加载统计
jstat -compiler pid # 编译统计
3.2 内存映射
# jmap - 内存映射
jmap [options] pid
# 堆信息
jmap -heap pid # 显示堆配置和使用情况
jmap -histo pid # 显示堆中对象统计
jmap -histo:live pid # 只显示存活对象
jmap -clstats pid # 显示类加载器统计
# 堆转储
jmap -dump:format=b,file=heap.hprof pid # 生成堆转储文件
jmap -dump:live,format=b,file=live_heap.hprof pid # 只转储存活对象
jmap -dump:format=b,file=heap_$(date +%Y%m%d_%H%M%S).hprof pid
# 堆分析
jmap -histo pid | head -20 # 显示占用内存最多的对象
jmap -histo pid | grep -E "java.lang.String|char\[\]" # 查找特定类型
4. 线程和并发分析
4.1 线程堆栈
# jstack - 线程堆栈跟踪
jstack [options] pid
# 基本使用
jstack pid # 显示所有线程堆栈
jstack -l pid # 显示锁的附加信息
jstack -m pid # 显示本地方法堆栈
jstack -F pid # 强制生成堆栈(进程假死时)
# 实用分析
jstack pid | grep -A 5 "BLOCKED" # 查找阻塞线程
jstack pid | grep -c "java.lang.Thread.State" # 统计线程数
jstack pid | grep "java.lang.Thread.State" | sort | uniq -c # 线程状态统计
4.2 线程分析脚本
# 查找CPU占用高的线程
#!/bin/bash
PID=$1
echo "Top CPU threads:"
top -H -p $PID -n 1 | grep -v "PID\|Tasks\|Cpu\|Mem\|Swap" | head -10 | while read line; do
tid=$(echo $line | awk '{print $1}')
hex_tid=$(printf "%x" $tid)
echo "Thread $tid (0x$hex_tid):"
jstack $PID | grep -A 20 "0x$hex_tid"
echo "---"
done
5. 多功能诊断工具
5.1 jcmd 命令
# jcmd - 多功能诊断工具
jcmd pid command [arguments]
# 基本信息
jcmd pid help # 显示可用命令
jcmd pid VM.version # JVM 版本信息
jcmd pid VM.uptime # JVM 运行时间
jcmd pid VM.system_properties # 系统属性
jcmd pid VM.command_line # 启动命令行
jcmd pid VM.flags # JVM 标志
# 内存管理
jcmd pid GC.run # 执行垃圾回收
jcmd pid GC.run_finalization # 执行终结器
jcmd pid VM.native_memory summary # 本地内存使用情况
# 线程管理
jcmd pid Thread.print # 打印线程堆栈
jcmd pid Thread.print -l # 包含锁信息
# 类信息
jcmd pid VM.class_hierarchy # 类层次结构
jcmd pid VM.classloader_stats # 类加载器统计
# 性能分析
jcmd pid JFR.start duration=60s filename=profile.jfr # 启动 JFR
jcmd pid JFR.stop # 停止 JFR
jcmd pid JFR.dump filename=dump.jfr # 转储 JFR
6. 图形化工具
6.1 JConsole
# jconsole - 图形化监控工具
jconsole [options] [connection...]
# 连接方式
jconsole # 启动并选择进程
jconsole pid # 直接连接到进程
jconsole host:port # 连接到远程 JVM
jconsole service:jmx:rmi:///jndi/rmi://host:port/jmxrmi
6.2 其他图形化工具
# jvisualvm - 可视化性能分析
jvisualvm [options]
# Java Mission Control (如果可用)
jmc
# 内存分析工具
jhat heapdump.hprof # 启动堆分析服务器
# 然后在浏览器中访问 http://localhost:7000
7. 安全和证书工具
7.1 密钥管理
# keytool - 密钥和证书管理
keytool [commands]
# 常用操作
keytool -genkey -alias mykey -keystore keystore.jks
keytool -list -keystore keystore.jks
keytool -delete -alias mykey -keystore keystore.jks
keytool -export -alias mykey -file mycert.crt -keystore keystore.jks
keytool -import -alias cacert -file ca.crt -keystore keystore.jks
7.2 JAR 签名
# jarsigner - JAR 签名工具
jarsigner [options] jarfile alias
# 签名和验证
jarsigner -keystore keystore.jks app.jar mykey
jarsigner -verify app.jar
jarsigner -verify -verbose app.jar
7.3 安全和证书工具
安全和证书工具
为什么需要安全和证书工具?
在企业级 Java 应用中,我们经常需要:
HTTPS 连接:访问第三方 API 或内部服务
数字签名:确保 JAR 包的完整性和来源可信
双向认证:客户端和服务器相互验证身份
证书管理:管理 SSL 证书、CA 证书等
密钥和证书管理 - keytool
keytool 是 Java 中管理密钥库(keystore)和证书的核心工具。
基本概念:
keystore:存储密钥和证书的文件
alias:密钥库中每个条目的别名
证书:包含公钥和身份信息的数字文档
常用操作示例:
# 生成密钥对和自签名证书
keytool -genkeypair -alias myserver -keyalg RSA -keysize 2048 \
-validity 365 -keystore server.jks -storepass changeit
# 查看密钥库内容
keytool -list -keystore server.jks -storepass changeit
# 导出证书
keytool -export -alias myserver -file server.crt \
-keystore server.jks -storepass changeit
# 导入 CA 证书
keytool -import -alias ca-cert -file ca.crt \
-keystore truststore.jks -storepass changeit
实际应用场景:
1、配置 Tomcat HTTPS
# 生成服务器证书
keytool -genkey -alias tomcat -keyalg RSA -keystore tomcat.jks
# 在 server.xml 中配置
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="conf/tomcat.jks" keystorePass="changeit"
clientAuth="false" sslProtocol="TLS" />
2、解决 SSL 证书问题
# 当 Java 应用访问 HTTPS 服务出现证书错误时
# 获取服务器证书
echo | openssl s_client -connect api.example.com:443 2>/dev/null | \
openssl x509 -outform PEM > api.crt
# 导入到 Java 信任库
keytool -import -alias api-server -file api.crt \
-keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
3、客户端证书认证
# 生成客户端证书
keytool -genkeypair -alias client -keyalg RSA -keystore client.jks
# 生成证书请求
keytool -certreq -alias client -file client.csr -keystore client.jks
# 导入签名后的证书
keytool -import -alias client -file client-signed.crt -keystore client.jks
JAR 签名 - jarsigner
jarsigner 用于对 JAR 文件进行数字签名,确保代码完整性。为什么需要 JAR 签名?
防篡改:确保 JAR 文件没有被修改
身份验证:验证 JAR 文件的发布者
安全策略:某些环境要求签名的 JAR 才能运行
基本使用:
# 签名 JAR 文件
jarsigner -keystore mykeys.jks -storepass keystorepass \
-keypass keypass myapp.jar myalias
# 验证签名
jarsigner -verify myapp.jar
# 详细验证信息
jarsigner -verify -verbose myapp.jar
# 验证证书链
jarsigner -verify -verbose -certs myapp.jar
实际应用场景:
1、企业内部应用分发
# 创建企业签名证书
keytool -genkeypair -alias company-sign -keyalg RSA -keysize 2048 \
-validity 1095 -keystore company.jks \
-dname "CN=Company Name,OU=IT,O=Company,C=US"
# 签名应用程序
jarsigner -keystore company.jks -storepass companypass \
enterprise-app.jar company-sign
# 验证签名
jarsigner -verify -verbose enterprise-app.jar
2、Java Web Start 应用
# 签名 JNLP 应用的所有 JAR
find . -name "*.jar" -exec jarsigner -keystore webstart.jks {} webstart-key \;
实用的安全管理脚本:
1、批量证书管理脚本
#!/bin/bash
# cert_manager.sh
KEYSTORE="application.jks"
STOREPASS="changeit"
# 检查证书有效期
check_cert_expiry() {
local alias=$1
echo "检查证书 $alias 的有效期:"
keytool -list -alias $alias -keystore $KEYSTORE -storepass $STOREPASS | \
grep "Valid from"
}
# 备份密钥库
backup_keystore() {
local backup_file="$KEYSTORE.backup.$(date +%Y%m%d_%H%M%S)"
cp $KEYSTORE $backup_file
echo "密钥库已备份到: $backup_file"
}
# 导入证书链
import_cert_chain() {
local cert_file=$1
local alias=$2
backup_keystore
keytool -import -alias $alias -file $cert_file \
-keystore $KEYSTORE -storepass $STOREPASS -noprompt
echo "证书 $alias 导入成功"
}
# 使用示例
# check_cert_expiry "server-cert"
# import_cert_chain "new-ca.crt" "new-ca"
2、SSL 连接测试脚本
#!/bin/bash
# ssl_test.sh
test_ssl_connection() {
local host=$1
local port=${2:-443}
echo "测试 SSL 连接: $host:$port"
# 测试连接
timeout 10 openssl s_client -connect $host:$port -servername $host \
-verify_return_error < /dev/null
if [ $? -eq 0 ]; then
echo "SSL 连接成功"
# 获取证书信息
echo "证书信息:"
echo | openssl s_client -connect $host:$port -servername $host 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates
else
echo "SSL 连接失败"
fi
}
# 使用示例
# test_ssl_connection "api.example.com" 443
常见问题解决方案
1、证书过期问题
# 检查系统默认信任库中的证书
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts \
-storepass changeit | grep -i "expired"
# 更新过期证书
keytool -delete -alias old-cert -keystore $JAVA_HOME/jre/lib/security/cacerts
keytool -import -alias new-cert -file new-cert.crt \
-keystore $JAVA_HOME/jre/lib/security/cacerts
2、自签名证书问题
# 创建自签名证书并添加到信任库
keytool -genkeypair -alias selfsigned -keyalg RSA -keystore temp.jks
keytool -export -alias selfsigned -file selfsigned.crt -keystore temp.jks
keytool -import -alias selfsigned -file selfsigned.crt \
-keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
3、证书链问题
# 验证完整的证书链
openssl verify -CAfile ca-chain.pem server.crt
# 如果链不完整,手动构建
cat server.crt intermediate.crt root.crt > chain.pem
生产环境最佳实践
定期检查证书有效期
#!/bin/bash
# 证书过期监控脚本
KEYSTORE="/path/to/production.jks"
STOREPASS="production-password"
DAYS_THRESHOLD=30
keytool -list -keystore $KEYSTORE -storepass $STOREPASS | \
while read line; do
if echo "$line" | grep -q "Valid from"; then
# 解析证书有效期并检查
# 如果即将过期,发送告警
echo "$line" | grep "Valid from" | \
awk '{print "证书即将过期: " $0}'
fi
done
自动化证书更新
#!/bin/bash
# 自动更新 Let's Encrypt 证书
certbot renew --quiet
# 转换为 Java keystore 格式
openssl pkcs12 -export -in cert.pem -inkey privkey.pem \
-out cert.p12 -name server -CAfile chain.pem
keytool -importkeystore -deststorepass changeit -destkeypass changeit \
-destkeystore server.jks -srckeystore cert.p12 -srcstoretype PKCS12
8. 实用监控脚本
8.1 内存监控脚本
memory_monitor
#!/bin/bash
# memory_monitor.sh
PID=$1
INTERVAL=${2:-5}
while true; do
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
gc_info=$(jstat -gc $PID | tail -1)
heap_info=$(jmap -heap $PID | grep -E "used|capacity")
echo "[$timestamp] GC: $gc_info"
echo "[$timestamp] Heap: $heap_info"
echo "---"
sleep $INTERVAL
done
8.2 线程监控脚本
thread_monitor
#!/bin/bash
# thread_monitor.sh
PID=$1
echo "Thread State Summary:"
jstack $PID | grep "java.lang.Thread.State" | awk '{print $2}' | sort | uniq -c | sort -nr
echo -e "\nBlocked Threads:"
jstack $PID | grep -B 2 -A 10 "BLOCKED"
echo -e "\nWaiting Threads:"
jstack $PID | grep -B 2 -A 10 "WAITING"
thread_monitor
#!/bin/bash
# thread_monitor.sh
PID=$1
echo "Thread State Summary:"
jstack $PID | grep "java.lang.Thread.State" | awk '{print $2}' | sort | uniq -c | sort -nr
echo -e "\nBlocked Threads:"
jstack $PID | grep -B 2 -A 10 "BLOCKED"
echo -e "\nWaiting Threads:"
jstack $PID | grep -B 2 -A 10 "WAITING"
8.3 全面诊断脚本
jvm_diagnosis
#!/bin/bash
# jvm_diagnosis.sh
PID=$1
OUTPUT_DIR="diagnosis_$(date +%Y%m%d_%H%M%S)"
mkdir -p $OUTPUT_DIR
cd $OUTPUT_DIR
echo "开始诊断 PID: $PID"
echo "输出目录: $OUTPUT_DIR"
# 基本信息
echo "=== 基本信息 ===" > basic_info.txt
jinfo -flags $PID >> basic_info.txt
jcmd $PID VM.version >> basic_info.txt
jcmd $PID VM.uptime >> basic_info.txt
# 内存信息
echo "=== 内存信息 ===" > memory_info.txt
jstat -gc $PID >> memory_info.txt
jmap -heap $PID >> memory_info.txt
jmap -histo $PID | head -50 >> memory_info.txt
# 线程信息
echo "=== 线程信息 ===" > thread_info.txt
jstack $PID > thread_dump.txt
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c >> thread_info.txt
# 生成堆转储
echo "生成堆转储..."
jmap -dump:format=b,file=heap_dump.hprof $PID
echo "诊断完成,结果保存在 $OUTPUT_DIR 目录中"
9. 常见问题和解决方案
9.1 权限问题
# 当遇到权限问题时
sudo -u java_user jstack pid # 使用相同用户执行
jstack -F pid # 强制执行(谨慎使用)
9.2 远程监控配置
# 启动时添加 JMX 参数
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
9.3 性能影响最小化
# 使用 jcmd 代替传统工具(推荐)
jcmd pid VM.flags # 代替 jinfo
jcmd pid Thread.print # 代替 jstack
jcmd pid GC.run_finalization # 代替直接 GC

浙公网安备 33010602011771号