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

 

posted @ 2018-04-11 15:10  lvlin241  阅读(144)  评论(0)    收藏  举报