Java 虚拟机优化指南:CMS垃圾回收器参数调优与性能监控工具详解
Java 虚拟机优化指南:CMS垃圾回收器参数调优与性能监控工具详解
引言
在高并发、大流量的企业级Java应用中,JVM参数的调优对系统性能至关重要。合理的JVM配置不仅能提高应用响应速度,还能减少垃圾回收造成的停顿时间,提升用户体验。本文将深入探讨CMS垃圾回收器的核心参数及其在大型电商系统中的优化策略,同时介绍几款实用的JVM监控与调优工具。
CMS垃圾回收器概述
CMS (Concurrent Mark Sweep) 是一种以获取最短回收停顿时间为目标的老年代垃圾回收器。CMS采用"标记-清除"算法,并且大部分工作是和应用线程一起并发执行的,仅在初始标记和重新标记阶段需要短暂停顿应用线程。
CMS核心参数详解
基础参数
- -XX:+UseConcMarkSweepGC:启用CMS垃圾回收器
- -XX:ConcGCThreads:并发GC线程数,通常设置为CPU核心数的1/4到1/2
- -XX:+UseCMSCompactAtFullCollection:在Full GC后进行碎片整理,减少内存碎片
- -XX:CMSFullGCsBeforeCompaction:设定多少次Full GC后进行一次碎片整理,默认值为0(表示每次Full GC后都进行整理)
触发条件参数
- -XX:CMSInitiatingOccupancyFraction:老年代使用率达到该阈值时触发CMS GC,默认为92(表示92%)
- -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(由CMSInitiatingOccupancyFraction参数指定),如不设置此参数,JVM仅在第一次使用设定值,后续会根据运行情况动态调整
性能优化参数
- -XX:+CMSScavengeBeforeRemark:在CMS GC的重新标记阶段前先执行一次minor GC,降低重新标记阶段的工作量和停顿时间
- -XX:+CMSParallellnitialMarkEnabled:在初始标记阶段使用多线程并行执行,缩短停顿时间
- -XX:+CMSParallelRemarkEnabled:在重新标记阶段使用多线程并行执行,缩短停顿时间
亿级流量电商系统JVM参数优化案例
大型电商系统通常分为多个子系统部署,如商品系统、库存系统、订单系统、促销系统和会员系统等。以核心的订单系统为例,针对8G内存的服务器,可分配4G内存给JVM。
优化思路与过程
初始配置
-Xms3072M -Xmx3072M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8
这个配置可能会因动态对象年龄判断机制导致对象过早进入老年代,从而引发频繁的Full GC。
优化配置1:明确指定年轻代大小
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8
通过明确指定年轻代大小为2048M,降低了对象因动态年龄判断而频繁进入老年代的问题。JVM调优的核心思路是让短期存活对象尽量留在Survivor区,避免进入老年代导致Full GC。
优化配置2:调整对象晋升老年代的条件
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M
- MaxTenuringThreshold=5:将对象晋升到老年代的年龄阈值从默认的15降为5。结合实际业务场景,minor GC通常每二三十秒发生一次,大多数对象几秒内就会变为垃圾。经过5次minor GC(约1-2分钟)仍存活的对象,可认为是长期存活对象,适合移至老年代。
- PretenureSizeThreshold=1M:超过1M的大对象直接在老年代分配,避免这类对象在Eden区和Survivor区之间复制,提高效率。
优化配置3:切换到ParNew+CMS收集器
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=3
当内存较大(经验值为超过4G)且系统对停顿时间敏感时,建议使用ParNew+CMS组合替代默认的Parallel收集器。
- CMSInitiatingOccupancyFraction=92:保持默认值,老年代使用率达到92%时触发CMS GC
- UseCMSCompactAtFullCollection:在Full GC后进行碎片整理
- CMSFullGCsBeforeCompaction=3:每3次Full GC后进行一次碎片整理
优化分析
在电商系统中,老年代中的对象主要包括:
- Spring容器中的Bean
- 线程池对象
- 初始化缓存数据
- 突发流量下产生的临时对象
通过合理配置年轻代大小和对象晋升条件,可以确保大多数临时对象在minor GC时被回收,只有真正长期存活的对象才进入老年代。在秒杀或大促期间,可能会有更多对象晋升到老年代,但通过上述配置,Full GC的频率可控制在半小时到一小时一次,且可能发生在流量高峰过后,对用户体验影响较小。
JVM调优工具详解
Java提供了多种调优工具帮助开发者分析和优化应用性能:
jstat (Java Statistics Monitoring Tool)
功能:监控Java应用运行时状态,尤其是GC相关的统计信息。
常用命令:
jstat -gc <pid> <interval> <count>:定期显示GC相关的堆内存和元空间使用情况S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 1024.0 1024.0 0.0 985.1 10240.0 5672.9 20480.0 15214.5 27648.0 26983.5 3584.0 3286.5 11 0.122 2 0.277 0.399jstat -gcutil <pid> <interval> <count>:定期显示GC的百分比使用情况S0 S1 E O M CCS YGC YGCT FGC FGCT GCT 0.00 96.20 55.40 74.29 97.60 91.70 11 0.122 2 0.277 0.399jstat -class <pid>:显示类加载和卸载的统计信息
适用场景:
- 监控GC行为,观察各代内存使用变化趋势
- 分析内存泄漏或GC性能问题
- 评估当前JVM参数配置的有效性
jmap (Java Memory Map)
功能:生成Java进程的内存快照,或查看内存使用情况。
常用命令:
jmap -heap <pid>:显示Java堆的详细信息,包括各代内存使用情况和GC算法Heap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize = 3221225472 (3072.0MB)NewSize = 2147483648 (2048.0MB)MaxNewSize = 2147483648 (2048.0MB)OldSize = 1073741824 (1024.0MB)NewRatio = 2SurvivorRatio = 8...jmap -histo[:live] <pid>:显示堆中对象的直方图,添加:live参数时只统计存活对象num #instances #bytes class name ----------------------------------------------1: 189981 45283000 [C2: 107433 11311720 java.lang.String3: 11251 5760960 [I...jmap -dump:format=b,file=heapdump.hprof <pid>:生成堆转储文件,用于后续分析
适用场景:
- 分析内存使用情况,找出占用内存最多的对象类型
- 生成堆转储文件,使用Eclipse MAT等工具进行深入分析
- 排查内存泄漏问题
jinfo (Java Configuration Info)
功能:查看和修改Java进程的JVM参数。
常用命令:
jinfo <pid>:显示当前JVM的配置信息jinfo -flag <flag_name> <pid>:查看特定JVM参数的当前值-XX:MaxHeapSize=3221225472jinfo -flag [+|-]<flag_name> <pid>:动态启用或禁用某个JVM标志(仅支持部分参数)
适用场景:
- 在运行时查看JVM配置,验证参数是否生效
- 动态调整支持热修改的JVM参数,无需重启应用
- 诊断排查JVM参数相关的问题
jstack (Java Stack Trace)
功能:生成Java进程的线程转储,显示所有线程的堆栈跟踪信息。
常用命令:
jstack <pid>:生成线程转储并输出到控制台jstack -l <pid>:生成线程转储,包含锁信息和监视器信息"main" #1 prio=5 os_prio=0 tid=0x00007f8a54009800 nid=0x1234 waiting on condition [0x00007f8a5e123000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)...
适用场景:
- 分析线程死锁问题
- 排查线程阻塞或CPU占用过高的问题
- 了解应用的线程使用情况和线程状态分布
综合使用策略
在实际调优过程中,通常需要结合使用多种工具:
-
内存泄漏分析流程:
- 使用
jstat长期监控GC频率和各代内存使用情况 - 发现老年代内存持续增长且GC无法回收时,使用
jmap生成堆转储 - 使用Eclipse MAT等工具分析堆转储,找出内存泄漏根源
- 使用
-
线程问题分析流程:
- 使用
top -Hp <pid>找出CPU使用率高的Java线程 - 将线程ID转换为十六进制:
printf "%x\n" <tid> - 使用
jstack生成线程转储,查找对应十六进制ID的线程 - 分析线程状态、执行堆栈和锁竞争情况
- 使用
-
JVM参数优化流程:
- 使用
jinfo查看当前JVM参数配置 - 使用
jstat监控GC行为,评估调优效果 - 根据监控结果调整JVM参数,如年轻代大小、GC触发阈值等
- 使用
jmap -heap验证参数变更是否生效
- 使用
最佳实践与建议
-
内存分配原则:
- 一般将可用物理内存的50%-70%分配给JVM
- 年轻代内存通常占JVM堆内存的1/3到1/2
- 调整Survivor比例,确保Eden区足够大,Survivor区能容纳Minor GC后存活的对象
-
对象晋升策略:
- 根据应用对象生命周期特点,合理设置MaxTenuringThreshold
- 对于瞬态业务(如电商秒杀),可适当降低该值,如设为5-8
- 对于稳定业务,可使用默认值15或调高,减少对象晋升到老年代的可能性
-
CMS参数调优:
- CMSInitiatingOccupancyFraction设置需平衡GC频率和内存利用率
- 高并发系统可适当降低该值(如70-80),提前触发GC,避免并发失败
- 配合CMSScavengeBeforeRemark参数,减少重新标记阶段停顿时间
-
碎片整理策略:
- 根据Full GC频率设置CMSFullGCsBeforeCompaction
- 对于频繁Full GC的系统,可设置为较大值,减少碎片整理带来的停顿
- 对于Full GC较少的系统,可设为较小值,保持内存紧凑
结语
JVM调优是一个持续优化的过程,需要根据应用特点和业务场景不断调整。通过合理配置CMS垃圾回收器参数,结合丰富的监控工具,可以显著提升Java应用的性能和稳定性。在实际调优过程中,应建立完善的监控体系,持续跟踪系统性能指标,及时发现并解决潜在问题。希望本文对您的JVM调优工作有所帮助!
相关文章:
Java 虚拟机优化指南:CMS垃圾回收器参数调优与性能监控工具详解
Java 虚拟机优化指南:CMS垃圾回收器参数调优与性能监控工具详解 引言 在高并发、大流量的企业级Java应用中,JVM参数的调优对系统性能至关重要。合理的JVM配置不仅能提高应用响应速度,还能减少垃圾回收造成的停顿时间,提升用户体…...
maven无法解析插件 org.apache.maven.plugins:maven-jar-plugin:3.4.1
解决流程 1.修改maven仓库库地址 2.删除本地的maven仓库 maven插件一直加载有问题: 无法解析插件 org.apache.maven.plugins:maven-jar-plugin:3.4.1 开始以为maven版本有问题,重装了maven,重装了idea工具。结果问题还是没解决。研究之后发现…...
Android Studio右上角Gradle 的Task展示不全
Android Studio 版本如下:Android Studio lguana|2023.21, 发现Gradle 的Tasks阉割严重,如下图,只显示一个other 解决方法如下:**Setting>Experimental>勾选Configure all gradle tasks during Gradle Sync(this can make…...
UDP协议 TCP协议(格式 超时重传 滑动窗口 拥塞控制...)
UDP协议 格式 UDP协议头部格式由8个字节组成,由4个2字节大小的字段组成。 源端口(Source Port,16 位): 发送端的端口号,标识数据从哪个端口发出。如果不需要,则可以填 0。 目标端口࿰…...
爱普生温补晶振 TG5032CFN高精度稳定时钟的典范
在科技日新月异的当下,众多领域对时钟信号的稳定性与精准度提出了极为严苛的要求。爱普生温补晶振TG5032CFN是一款高稳定性温度补偿晶体振荡器(TCXO)。该器件通过内置温度补偿电路,有效抑制环境温度变化对频率稳定性的影响&#x…...
今日头条文章爬虫教程
今日头条文章爬虫教程 随着互联网的发展,新闻资讯类平台如今日头条积累了海量的数据。对于数据分析师、研究人员等群体来说,获取这些数据进行分析和研究具有重要的价值。本文将介绍如何使用Python编写爬虫,爬取今日头条的文章数据。 一、准…...
【网络安全工程】任务11:路由器配置与静态路由配置
目录 一、概念 二、路由器配置 三、配置静态路由CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog 一、概念 1、路由器的作用:通过路由表进行数据的转发。 2、交换机的作用:通过学习和识别 MAC 地址,依据 M…...
Compose 实践与探索二 —— 状态订阅与自动更新1
1、自定义 Composable 为什么所有组件都要加 Composable 注解才可以使用? 这是因为 Compose 需要通过 Compose 的编译器插件(Compose Compiler Plugin)在组件函数中增加一些参数,这些参数在调用时有用。通过编译器增加这些参数&…...
linux下文件读写操作
Linux下,文件I/O是操作系统与文件系统之间进行数据传输的关键部分。文件I/O操作允许程序读取和写入文件,管理文件的打开、关闭、创建和删除等操作。 1. 文件描述符 在Linux中,每个打开的文件都由一个文件描述符来表示。文件描述符是一个非负…...
嵌入式学习第二十四天--网络 服务器
服务器模型 tcp服务器: socket bind listen accept recv/send close 1.支持多客户端访问 //单循环服务器 socket bind listen while(1) { accept while(1) { recv/send } } close 2.支持多客户端同时访问 (并发能力) 并发服务器 socket bind …...
Uniapp组件 Textarea 字数统计和限制
Uniapp Textarea 字数统计和限制 在 Uniapp 中,可以通过监听 textarea 的 input 事件来实现字数统计功能。以下是一个简单的示例,展示如何在 textarea 的右下角显示输入的字符数。 示例代码 首先,在模板中定义一个 textarea 元素ÿ…...
【Java 面试 八股文】计算机网络篇
操作系统篇 1. 什么是HTTP? HTTP 和 HTTPS 的区别?2. 为什么说HTTPS比HTTP安全? HTTPS是如何保证安全的?3. 如何理解UDP 和 TCP? 区别? 应用场景?3.1 TCP 和 UDP 的特点3.2 适用场景 4. 如何理解TCP/IP协议?5. DNS协议 是什么?说说DNS 完整的查询…...
Webservice创建
Webservice创建 服务端创建 3层架构 service注解(commom模块) serviceimpl(server) 服务端拦截器的编写 客户端拦截器 客户端调用服务端(CXF代理) 客户端调用服务端(动态模式调用&a…...
使用VS Code remote ssh进行远程开发的笔记
本文是在VS Code中使用 remote ssh 进行开发的笔记。 安装插件 打开VS Code,在扩展区找到remote相关插件,安装之。下图中红色框出来的是已经安装了的插件(圆圈处即为Remote Explorer)。 实践 连接服务器 新建连接:…...
C语言每日一练——day_3(快速上手C语言)
引言 针对初学者,每日练习几个题,快速上手C语言。第三天。(会连续更新) 采用在线OJ的形式 什么是在线OJ? 在线判题系统(英语:Online Judge,缩写OJ)是一种在编程竞赛中用…...
Linux基本操作指令4
1、查看Ubuntu的版本 lsb_release -a 2、在 Ubuntu 下安装 OpenGL Library sudo apt-get install libglu1-mesa-dev 3、终止当前运行的进程 Ctrl C//默认情况 Ctrl Shift C//若修改了复制快捷键为CtrlC的情况 4、快速打开终端 CtrlAltT 5、关闭终端 Ctrl Shift W…...
PostgreSQL - Windows PostgreSQL 下载与安装
Windows PostgreSQL 下载与安装 1、PostgreSQL 下载 下载地址:https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 2、PostgreSQL 安装 启动安装程序 -> 点击 【Next】 指定安装路径 -> 点击 【Next】 默认勾选 -> 点击 【Next】 指…...
JVM 的主要组成部分及其作用?
创作内容丰富的干货文章很费心力,感谢点过此文章的读者,点一个关注鼓励一下作者,激励他分享更多的精彩好文,谢谢大家! JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执…...
华为eNSP:配置P2P网络类型
一、什么是P2P网络类型 P2P(Point-to-Point)网络类型 是 OSPF(开放最短路径优先)协议中的一种网络类型,用于描述两个路由器之间直接相连的点对点链路。P2P 网络类型通常用于串行链路(如 PPP 或 HDLC 封装&…...
通过数据集微调LLM后怎么调用
通过数据集微调LLM后怎么调用 1. 导入必要的库 from transformers import AutoTokenizer, AutoModelForCausalLMAutoTokenizer:这是 transformers 库中的一个实用类,它能够根据指定的模型名称或路径自动选择合适的分词器。分词器的主要作用是将输入的文本字符串转换为模型可…...
thinkphp+mysql+cast解决text类型字段的文本型数字排序错误的方法 - 数据库文本字段排序ASC、DESC的失效问题
TP中使用cast order $lists AmdCommonTable::where(..............) ->field(*,CAST(w6 AS UNSIGNED) as sort) ->order(sort, asc) ->select() ->toArray(); 先转换为数字,再order by 效果对比 (1/2) 不ok - 直接order by 某字段 asc - 只能按照文本…...
【Manus资料合集】激活码内测渠道+《Manus Al:Agent应用的ChatGPT时刻》(附资源)
DeepSeek 之后,又一个AI沸腾,冲击的不仅仅是通用大模型。 ——全球首款通用AI Agent的破圈启示录 2025年3月6日凌晨,全球AI圈被一款名为Manus的产品彻底点燃。由Monica团队(隶属中国夜莺科技)推出的“全球首款通用AI…...
C++----红黑树map和set的封装
一、红黑树 1.概念 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出2倍࿰…...
【报错】微信小程序预览报错”60001“
1.问题描述 我在微信开发者工具写小程序时,使用http://localhost:8080是可以请求成功的,数据全都可以无报错,但是点击【预览】,用手机扫描二维码浏览时,发现前端图片无返回且报错60001(打开开发者模式查看日…...
软考 数据通信基础——信道
信道特性 带宽 在模拟信号里频率的差,表示信道能通过的频率 在数字信号里表示最大传输速率,单位用bit/s 通常用W表示 波特率 即码元速率,码元可看作一个时间周期 码元速率B2W也可写成B1/T 码元种类n和码元信息量个数N存在以下关系 Nl…...
windows 平台如何点击网页上的url ,会打开远程桌面连接服务器
你可以使用自定义协议方案(Protocol Scheme)实现网页上点击URL后自动启动远程桌面连接(mstsc),参考你提供的C代码思路,如下实现: 第一步:注册自定义协议 使用类似openmstsc://协议…...
uni-app开发的App和H5嵌套封装的App,以及原生App有什么区别
uni-app 开发的 App 和 H5 嵌套封装的 App 是两种不同的开发模式,虽然它们都可以实现跨平台开发,但在技术实现、性能、功能支持等方面有显著区别。以下是详细对比: 1. uni-app 开发的 App uni-app 是一个基于 Vue.js 的跨平台开发框架&#…...
Anaconda中虚拟环境安装g++和gcc相同版本
安装torchSDF的时候遇到的,这是g和gcc版本不一致的问题 gcc: fatal error: cannot execute cc1plus: execvp: No such file or directory compilation terminated.查看gcc, g版本 gcc --version | head -n1 g --version | head -n1发现gcc的是anaconda中的&#x…...
Docker数据管理,端口映射与容器互联
1.Docker 数据管理 在生产环境中使用 Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。 容器中的管理数据主要有两种方式: 数据卷(Data Volumns)&a…...
部署前后端项目
部署项目 liunx 软件安装 软件安装方式 在Linux系统中,安装软件的方式主要有四种,这四种安装方式的特点如下: 建议nginx、MySQL、Redis等等使用docker安装,会很便捷,这里只演示JDK、ngxin手动的安装 安装JDK 上述我…...
