当前位置: 首页 > news >正文

JVM调优详解(二)

目录

JVM内存分配详解

一、参数解析

二、详细计算过程(MB单位)

三、内存分布可视化

四、关键配置解析

五、监控脚本详解

六、参数优化建议

七、配置验证流程


JVM内存分配详解

root 40014 1 24 11:43 pts/0 00:01:53 /usr/local/jdk/jdk1.8.0_161/bin/java -Dname=ldey-admin.jar -Duser.timezone=Asia/Shanghai -Xms1024m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -Xloggc:/usr/local/ldey/jar/logs/ldey-admin-gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=15 -XX:+UseParallelGC -XX:+UseParallelOldGC -jar /usr/local/ldey/jar/ldey-admin.jar --spring.profiles.active=druid-prod

jstat -gc 40014

S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT

43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

#每秒统计垃圾回收的堆信息,打印10次,

    jstat -gc 40014 1000 10

    • pid: java进程号
    • interval: 间隔时间,单位为秒或毫秒
    • count: 打印次数,不填则默认一直打印

    S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    43520.0 42496.0 25192.3 0.0 438272.0 400934.9 524288.0 49220.6 86272.0 82255.7 10752.0 9929.8 10 0.292 0 0.000 0.292

    如果需要转换为MB或GB,可以:

    1. 手动计算:KB值/1024=MB
    2. 使用awk处理:

    jstat -gc <pid> 1000 1 | awk 'NR==1 {print $0} NR>1 {for(i=1;i<=NF;i++) {if($i~/^[0-9]/) printf "%.1f ", $i/1024; else printf "%s ", $i} printf "\n"}'

    jstat -gc 是 JVM 内置的监控工具,用于显示堆内存各区域的实际容量和使用量(KB单位)。

    基本用法: jstat -gc <pid> [interval] [count]

    • <pid>:Java 进程 ID
    • interval:采样间隔(毫秒)
    • count:采样次数

    命令参数详解:

    列名

    全称

    说明

    单位

    S0C

    Survivor 0 Capacity

    新生代 Survivor 0区容量

    KB

    S1C

    Survivor 1 Capacity

    新生代 Survivor 1区容量

    KB

    S0U

    Survivor 0 Used

    新生代 Survivor 0区已使用

    KB

    S1U

    Survivor 1 Used

    新生代 Survivor 1区已使用

    KB

    EC

    Eden Capacity

    新生代 Eden区容量

    KB

    EU

    Eden Used

    新生代 Eden区已使用

    KB

    OC

    Old Capacity

    老年代容量

    KB

    OU

    Old Used

    老年代已使用

    KB

    MC

    Metaspace Capacity

    元空间容量

    KB

    MU

    Metaspace Used

    元空间已使用

    KB

    CCSC

    Compressed Class Space Capacity

    压缩类空间容量

    KB

    CCSU

    Compressed Class Space Used

    压缩类空间已使用

    KB

    YGC

    Young GC Count

    年轻代GC次数

    YGCT

    Young GC Time

    年轻代GC累计时间

    FGC

    Full GC Count

    Full GC次数

    FGCT

    Full GC Time

    Full GC累计时间

    GCT

    Total GC Time

    GC总时间

    jstat -gcutil 是 JVM 监控工具,用于显示垃圾回收统计信息的百分比格式,比 jstat -gc 更直观。

    基本用法: jstat -gcutil <pid> [interval] [count]

    • <pid>:Java 进程 ID
    • interval:采样间隔(毫秒)
    • count:采样次数

    列名

    全称

    含义

    正常范围

    S0

    Survivor 0 使用率

    Survivor 0 区已用百分比

    0%-100%

    S1

    Survivor 1 使用率

    Survivor 1 区已用百分比

    0%-100%

    E

    Eden 使用率

    Eden 区已用百分比

    <90%(避免频繁GC)

    O

    Old 使用率

    老年代已用百分比

    <75%(预警阈值)

    M

    Metaspace 使用率

    元空间已用百分比

    <80%

    CCS

    Compressed Class Space 使用率

    压缩类空间使用率

    <80%

    YGC

    Young GC Count

    年轻代GC次数

    -

    YGCT

    Young GC Time

    年轻代GC总时间(秒)

    -

    FGC

    Full GC Count

    Full GC次数

    越少越好

    FGCT

    Full GC Time

    Full GC总时间(秒)

    -

    GCT

    Total GC Time

    GC总时间(秒)

    -

    一、参数解析

    -Xms1024m -Xmx1024m # 固定堆内存为1024MB(避免动态扩展)
    -XX:NewRatio=1 # 新生代与老年代1:1分配
    -XX:SurvivorRatio=6 # Eden区与单个Survivor区6:1分配
    -XX:MaxTenuringThreshold=15 # 对象经历15次GC才晋升老年代

    二、详细计算过程(MB单位)

    总堆内存分配

    初始值和最大值相同都为1024MB

    即总堆内存 = Xms值 = Xmx值 = 1024MB

    新生代与老年代划分

    新生代 = 总堆 / (NewRatio + 1) = 1024 / (1 + 1) = 512MB
    老年代 = 总堆 - 新生代 = 1024 - 512 = 512MB

    新生代内部区域计算

    总比例份数 = SurvivorRatio + 2 = 6 + 2 = 8份
    Eden区 = 新生代 × (SurvivorRatio/总份数) = 512 × (6/8) = 384MB
    单个Survivor区 = 新生代 × (1/总份数) = 512 × (1/8) = 64MB

    新生代 = Eden区 + Survivor 0 区 + Survivor 1区 = 384 + 64 + 64 = 512MB

    元空间内存

    元空间初始 = 128MB(-XX:MetaspaceSize)
    元空间最大 = 512MB(-XX:MaxMetaspaceSize)

    三、内存分布可视化

    理论计算:

    堆内存 (1024MB)
    ├─ 新生代 (512MB)
    │ ├─ Eden区 (384MB) # 新对象分配区域
    │ ├─ Survivor0 (64MB) # From Survivor
    │ └─ Survivor1 (64MB) # To Survivor
    └─ 老年代 (512MB) # 长期存活对象

    实际分配:

    堆内存 (1024MB)
    ├─ 新生代 (512MB)
    │ ├─ Eden区 (428.5MB) # 新对象分配区域
    │ ├─ Survivor0 (42.5MB) # From Survivor
    │ └─ Survivor1 (41.0MB) # To Survivor
    └─ 老年代 (512MB) # 长期存活对象

    特别注意:JVM 的内存分配可能与理论计算不完全一致,这通常是由以下几个原因导致的

    1.JVM 内存对齐和最小/最大限制
          JVM 在分配内存时可能会进行内存对齐(Memory Alignment),以确保性能优化。例如:

    某些 JVM 实现会向上取整到特定倍数(如 1MB、4MB 等),导致实际分配的内存略大于计算值。Survivor 区的最小限制:即使 SurvivorRatio=6,某些 JVM 可能会强制 Survivor 区至少占用一定比例(如 5%),而不是严格按照 6:1:1 分配。

    2.自适应调整(Adaptive Sizing)
          如果启用了 -XX:+UseAdaptiveSizePolicy(Parallel GC 默认开启),JVM 可能会动态调整 Eden 和 Survivor 的比例,以优化 GC 性能。这可能导致:Eden 区比计算值更大,Survivor 区更小。

    老年代的实际占用可能因晋升策略而变化。

    3.元空间(Metaspace)的影响
         虽然 -Xmx 和 -Xms 控制堆内存,但 Metaspace(类元数据) 是独立分配的:

         如果 Metaspace 占用过高,可能会影响可用堆内存(但通常不会直接影响 NewRatio 分         配)。可以使用 jstat -gc 查看 Metaspace 的实际使用情况。

    4.垃圾收集器(GC)的特定行为
          不同的 GC 对内存分配策略不同:

          Parallel GC(-XX:+UseParallelGC):默认开启 UseAdaptiveSizePolicy,可能导致              Survivor 区大小动态变化。

          G1 GC(-XX:+UseG1GC):没有固定的 NewRatio,而是按 Region 动态分配。

          CMS(-XX:+UseConcMarkSweepGC):可能更严格遵循 NewRatio,但仍可能受 JVM 优化影响。

    5.系统限制和 JVM 版本差异
          操作系统内存限制:如果物理内存不足,JVM 可能无法分配全部 -Xmx 内存。不同 JVM 版本(如 OpenJDK vs. Oracle JDK)可能有不同的内存分配策略。

    四、关键配置解析

    SurvivorRatio优化

    原始值30:1:1 → 调整后6:1:1
    Survivor区从16MB → 64MB(理论值)

    效果:减少对象过早晋升老年代

    晋升阈值

    -XX:MaxTenuringThreshold=15

    • 对象需经历15次Minor GC才晋升
    • 配合更大的Survivor区显著降低老年代压力

    GC策略

    -XX:+UseParallelGC -XX:+UseParallelOldGC

    • Parallel Scavenge + Parallel Old组合
    • 吞吐量优先,适合后台处理型应用

    五、监控脚本详解

    #!/bin/sh
    pid=`ps -ef | grep ldey | grep -v grep | awk '{print $2}'`
    # 默认1秒刷新一次
    interval=1000
    # 打印次数
    count=10jstat -gc $pid $interval $count | awk '
    BEGIN {# 列宽对齐的MB单位表头header="    S0C_MB   S1C_MB    S0U_MB   S1U_MB  EC_MB     EU_MB      OC_MB       OU_MB   MC_MB    MU_MB     CCSC_MB  CCSU_MB  YGC   YGCT_秒    FGC  FGCT_秒  GCT_秒"gsub(/_[A-Z秒]+/, "\033[1;36m&\033[0m", header)  # 给单位加蓝色print header
    }
    NR>1 {# 设置颜色:Survivor黄,Eden蓝,Old红,元空间紫printf "\033[33m%8.1f\033[0m \033[33m%8.1f\033[0m ", $1/1024, $2/1024;printf "\033[32m%8.1f\033[0m \033[32m%8.1f\033[0m ", $3/1024, $4/1024;printf "\033[34m%9.1f\033[0m \033[34m%9.1f\033[0m ", $5/1024, $6/1024;printf "\033[31m%10.1f\033[0m \033[31m%10.1f\033[0m ", $7/1024, $8/1024;printf "\033[35m%8.1f %8.1f %8.1f %8.1f\033[0m ", $9/1024, $10/1024, $11/1024, $12/1024;printf "%6d \033[1;33m%8.3f\033[0m %6d \033[1;31m%8.3f\033[0m %8.3f\n", $13, $14, $15, $16, $17
    }'jstat -gcutil $pid $interval $count | awk '
    BEGIN {# 列宽对齐的MB单位表头header="     S0_%    S1_%     E_%      O_%       M_%       CCS_%      YGC         YGCT_秒  FGC  FGCT_秒  GCT_秒"gsub(/_[%秒]+/, "\033[1;36m&\033[0m", header)  # 给单位加蓝色print header
    }
    NR>1 {# 设置颜色:Survivor黄,Eden蓝,Old红,元空间紫printf "\033[33m%8.1f\033[0m \033[33m%8.1f\033[0m ", $1, $2;printf "\033[32m%8.1f\033[0m \033[32m%8.1f\033[0m ", $3, $4;printf "\033[34m%9.1f\033[0m \033[34m%9.1f\033[0m ", $5, $6;printf "\033[31m%10.1f\033[0m \033[31m%10.1f\033[0m ", $7, $8;printf "%6d \033[1;33m%8.3f\033[0m %8.3f\n", $9, $10, $11
    }'# 获取新生代 Eden 区使用率
    EDEN_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print $3}')
    if (( $(echo "$EDEN_USAGE > 80" | bc -l) )); thenecho "警告:新生代Eden区使用率超过 80%,当前值: ${EDEN_USAGE}%"
    elseecho "新生代Eden区使用率正常: ${EDEN_USAGE}%"
    fi# 获取新生代 Survivor 区使用率(取 S0 和 S1 的最大值)
    SURVIVOR_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print ($1 > $2 ? $1 : $2)}')# 判断是否 > 80%
    if (( $(echo "$SURVIVOR_USAGE > 80" | bc -l) )); thenecho "警告:新生代Survivor区使用率超过 80%,当前值: ${SURVIVOR_USAGE}%"
    elseecho "新生代Survivor区使用率正常: ${SURVIVOR_USAGE}%"
    fi# 判断老年代的使用率
    OLD_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print $4}')
    if (( $(echo "$OLD_USAGE > 80" | bc -l) )); thenecho "警告:老年代使用率超过 80%,当前值: ${OLD_USAGE}%"
    elseecho "老年代使用率正常: ${OLD_USAGE}%"
    fi

    执行效果示例:

    六、参数优化建议

    新生代Eden区监控

    # 获取新生代 Eden 区使用率
    EDEN_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print $3}')
    if (( $(echo "$EDEN_USAGE > 80" | bc -l) )); thenecho "警告:新生代Eden区使用率超过 80%,当前值: ${EDEN_USAGE}%"
    elseecho "新生代Eden区使用率正常: ${EDEN_USAGE}%"
    fi

    新生代Survivor区监控

    # 计算Survivor使用率
    # 获取新生代 Survivor 区使用率(取 S0 和 S1 的最大值)
    SURVIVOR_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print ($1 > $2 ? $1 : $2)}')# 判断是否 > 80%
    if (( $(echo "$SURVIVOR_USAGE > 80" | bc -l) )); thenecho "警告:新生代Survivor区使用率超过 80%,当前值: ${SURVIVOR_USAGE}%"
    elseecho "新生代Survivor区使用率正常: ${SURVIVOR_USAGE}%"
    fi
    # 若持续 > 80%,需考虑增大SurvivorRatio

    老年代区监控

    # 判断老年代的使用率
    OLD_USAGE=$(jstat -gcutil $pid 1000 1 | awk 'NR==2 {print $4}')
    if (( $(echo "$OLD_USAGE > 80" | bc -l) )); thenecho "警告:老年代使用率超过 80%,当前值: ${OLD_USAGE}%"
    elseecho "老年代使用率正常: ${OLD_USAGE}%"
    fi

    GC日志分析

    # 检查Full GC频率
    grep "Full GC" ldey-admin-gc.log | wc -l

    七、配置验证流程

    启动应用后立即检查

    jmap -heap <PID>

    压测期间监控

    watch -n 1 'jstat -gc <pid> | awk "...MB转换脚本..."'

    长期运行分析

    # 使用GCViewer分析日志

    gcviewer ldey-admin-gc.log

    该配置通过精细的内存划分,在吞吐量和内存效率之间取得平衡,特别适合中等规模的Spring Boot应用。监控脚本可清晰直观的展现JVM内存区域的占用情况,而更好的调整,以助于让JVM运行达到最优,在实际运行中建议结合业务峰值持续优化。

    相关文章:

  • AI大模型之机器学习理论及实践:监督学习-机器学习的核心基石
  • 北斗导航深度接入小程序打车:高精度定位如何解决定位漂移难题?
  • 数据结构day1
  • HTML基础结构
  • AWS ACM 重磅上线:公有 SSL/TLS 证书现可导出,突破 AWS 边界! (突出新功能的重要性和突破性)
  • [Hestia]开源网络服务器控制面板,快速、可靠、开源
  • 【计算复杂度】普通卷积 VS 深度可分离卷积
  • 深入解析AIGC:技术原理、应用场景与未来挑战
  • 【附源码】考试报名系统设计与实现+SpringBoot + Vue (前后端分离)
  • 多智能体协同的力量:赋能AI安全报告系统的智能设计之道
  • 运行go程序时出现的同包多文件不能调用的问题
  • Python datetime模块详解
  • 【GNSS定位算法】Chapter.2 导航定位算法软件学习——Ginav(二)SPP算法 [2025年6月]
  • Neo4j.5.X社区版创建数据库和切换数据库
  • 最近小峰一直在忙国际化项目,确实有点分身乏术... [特殊字符] 不过! 我正紧锣密鼓准备一系列干货文章/深度解析
  • Flink SQL执行流程深度剖析:从SQL语句到分布式执行
  • Redis集群性能优化实战指南
  • 开启游戏新时代:神经网络渲染技术实现重大跨越
  • 【C++】C++中的虚函数和多态的定义与使用
  • [3-01-02].第15节:调优工具 - 查看 SQL 执行成本
  • 温岭手机网站建设/域名解析
  • 沧州市做网站的/南宁网络推广品牌
  • php怎么用来做网站/营销型网站建设案例
  • 个人工作室网站怎么做/网络推广一般都干啥
  • 北京百度seo公司/seo综合查询中的具体内容有哪些
  • 如何建立网站是什么/码迷seo