JVM性能调优的6大步骤,及关键调优参数详解

文章详细介绍了JVM内存调优的目标,特别是减少FullGC的次数,分析了导致FullGC的原因,并提供了调优的方法和步骤,包括监控GC状态、生成堆dump文件、使用工具分析、调整GC参数等。此外,文章还提及了关键的JVM参数设置,如年轻代与年老代的比例,以及线程堆栈的配置,并推荐了使用如VisualVM和MAT这样的工具进行分析。

一、JVM内存调优

对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数。

1.Full GC

会对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比较慢,因此应该尽可能减少Full GC的次数。

2.导致Full GC的原因

1)年老代(Tenured)被写满

调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避免直接在旧生代创建对象 。

2)持久代Pemanet Generation空间不足

增大Perm Gen空间,避免太多静态对象 , 控制好新生代和旧生代的比例

3)System.gc()被显示调用

垃圾回收不要手动触发,尽量依靠JVM自身的机制

在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节,下面详细介绍对应JVM调优的方法和步骤。

二、JVM性能调优方法和步骤

1.监控GC的状态

使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化。

举一个例子: 系统崩溃前的一些现象:

  • 每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4、5s
  • FullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC
  • 年老代的内存越来越大并且每次FullGC后年老代没有内存被释放

之后系统会无法响应新的请求,逐渐到达OutOfMemoryError的临界值,这个时候就需要分析JVM内存快照dump。

2.生成堆的dump文件

通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动JMX可以通过Java的jmap命令来生成该文件。

3.分析dump文件

打开这个3G的堆信息文件,显然一般的Window系统没有这么大的内存,必须借助高配置的Linux,几种工具打开该文件:

  • Visual VM
  • IBM HeapAnalyzer
  • JDK 自带的Hprof工具
  • Mat(Eclipse专门的静态内存分析工具)推荐使用

备注:文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。

4.分析结果,判断是否需要优化

如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化,如果GC时间超过1-3秒,或者频繁GC,则必须优化。

注:如果满足下面的指标,则一般不需要进行GC:

  • Minor GC执行时间不到50ms;
  • Minor GC执行不频繁,约10秒一次;
  • Full GC执行时间不到1s;
  • Full GC执行频率不算频繁,不低于10分钟1次;

5.调整GC类型和内存分配

如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。

6.不断的分析和调整

通过不断的试验和试错,分析并找到最合适的参数,如果找到了最合适的参数,则将这些参数应用到所有服务器。

cms参数优化步流程

下面我再继续介绍下JVM的关键参数配置(仅用于参考)。

JVM调优参数参考

1.针对JVM堆的设置,一般可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,通常把最大、最小设置为相同的值;

2.年轻代和年老代将根据默认的比例(1:2)分配堆内存, 可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代。

比如年轻代,通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小。

3.年轻代和年老代设置多大才算合理

1)更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC

2)更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率

如何选择应该依赖应用程序对象生命周期的分布情况: 如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性。

在抉择时应该根 据以下两点:

(1)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 。

(2)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。

4.在配置较好的机器上(比如多核、大内存),可以为年老代选择并行收集算法-XX:+UseParallelOldGC****。

5.线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。

理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。

觉得不错请点赞支持下。

<think>我们正在讨论JVM性能,根据用户的问题,他想要获取JVM性能的相关信息,包括方法和技巧。同时,用户提供了几个引用,但这些引用是关于JVM性能的概述性内容,我们需要结合这些引用以及我们对JVM的知识来回答。 注意:用户之前的问题是关于Java类加载机制,现在转向了JVM性能,因此我们要专注于部分。 回答结构: 1. 引言:简要介绍JVM性能的重要性。 2. 目标:明确的目标指标(如吞吐量、延迟、内存占用等)。 3. 方法:详细描述的常用方法和技巧(包括参数配置、监控工具、代码化等)。 4. 实战步骤:给出一个典型的步骤(参考引用[4]中的步骤)。 5. 注意事项:中需要注意的问题。 6. 总结。 同时,根据要求,我们需要在回答末尾生成相关问题。 由于引用中提供了一些信息,我们可以适当引用,但主要依靠我们的知识库来构建详细内容。 注意:引用标记[^1]、[^2]等需要放在引用内容的后面,并且自然。 </think>### JVM性能方法与技巧详解 JVM性能是提升Java应用效率的关键,核心目标包括降低GC频率、减少STW时间、化内存使用和提高吞吐量。以下是系统化的方法和实战技巧: --- #### 一、核心目标 1. **内存化** - 减少堆内存碎片和Full GC次数 - 平衡新生代(Young Gen)和老年代(Old Gen)比例 - 示例参数: ```bash -Xms4g -Xmx4g # 堆内存初始值=最值,避免动态扩容开销 -XX:NewRatio=2 # 新生代:老年代=1:2 ``` 2. **延迟化** - 缩短GC暂停时间(STW),尤其是CMS/G1的并发阶段 - 关键指标:`GC Pause Time < 200ms`(视业务敏感度整) 3. **吞吐量化** - 提高应用有效工作时间占比 - 目标:`Throughput = (总运行时间 - GC时间) / 总运行时间 > 95%` [^4] --- #### 二、方法与技巧 ##### 1. **内存参数** | 参数 | 作用说明 | 场景 | |---------------------|----------------------------------|----------------------------| | `-XX:MaxTenuringThreshold` | 对象晋升老年代年龄阈值 | 减少过早晋升导致的Full GC | | `-XX:SurvivorRatio=8` | Eden与Survivor区比例(默认8:1:1)| 对象存活率高的应用 | | `-XX:+UseG1GC` | 启用G1垃圾收集器 | 堆(>4GB)或低延迟需求 | **实战技巧**: - 若Minor GC频繁,增加`-Xmn`(新生代小) - 若Full GC频繁,增老年代或降低`-XX:MaxTenuringThreshold` ##### 2. **GC日志分析与监控** - **启用详细GC日志**: ```bash -XX:+PrintGCDetails -Xloggc:/path/to/gc.log ``` - **关键分析工具**: - `jstat -gcutil <pid> 1000`:实时监控GC各分区使用率 - `jmap -dump:format=b,file=heapdump.hprof <pid>`:生成堆转储文件 - **可视化工具**:GCViewer、MAT(Memory Analyzer)分析内存泄漏[^3] ##### 3. **垃圾收集器选择策略** | 收集器 | 适用场景 | 重点 | |----------------|----------------------------------|----------------------------| | **Parallel GC** | 高吞吐量应用(如批处理) | `-XX:ParallelGCThreads` | | **CMS** | 低延迟Web服务(JDK8及之前) | `-XX:CMSInitiatingOccupancyFraction` | | **G1** | 内存+均衡吞吐/延迟(JDK9+默认) | `-XX:MaxGCPauseMillis=200` | > **案例**:某电商平台通过G1替换CMS,将99% GC暂停从500ms降至50ms[^3]。 ##### 4. **代码层化** - **减少短命对象**:避免循环内创建临时对象 - **软/弱引用管理**:缓存使用`WeakHashMap`防止内存泄漏 - **堆外内存控制**:Netty等框架需限制`-XX:MaxDirectMemorySize` --- #### 三、标准化流程 [^4] 1. **基线分析**:无参数运行,采集GC日志和性能指标 2. **瓶颈定位**: - 高频Full GC → 检查老年代内存或对象泄漏 - 长暂停时间 → 化GC算法或整`MaxGCPauseMillis` 3. **参数迭代**:每次仅修改1-2个参数,对比测试 4. **监控验证**:使用APM工具(如SkyWalking)跟踪后效果 --- #### 四、注意事项 1. **避免过度**:化代码和架构,JVM参数为最后手段 2. **版本差异**:JDK11+的ZGC/Shenandoah适用于超低延迟场景(暂停<10ms) 3. **监控持续性**:生产环境需持续监控`jstat`和GC日志[^2] > **本质**:在内存、吞吐量、延迟三者间寻找平衡点,公式表达: > $$\text{系统效率} = \frac{\text{有效计算时间}}{\text{总时间}} = 1 - \frac{\text{GC时间} + \text{其他开销}}{\text{总时间}}$$ --- ### 总结 JVM需结合监控数据、GC日志和业务场景迭代推进。先通过`jstat`/堆转储定位瓶颈,再针对性整内存分区或GC算法。对于多数应用,G1+合理堆小配置即可满足需求,复杂场景可探索ZGC[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值