0

0

常用的JVM性能调优参数有哪些?(堆大小、垃圾收集器等)

幻影之瞳

幻影之瞳

发布时间:2025-09-03 16:18:01

|

1111人浏览过

|

来源于php中文网

原创

答案:jvm性能调优需重点关注堆内存设置、垃圾收集器选择、新生代与元空间配置及线程栈大小等参数。合理设置-xms和-xmx可避免内存抖动,建议初始与最大堆内存相等,通常为物理内存的25%~50%。g1 gc是java 9+默认收集器,适合多数中大型应用,兼顾吞吐量与延迟;zgc和shenandoah适用于超大堆和低延迟场景。新生代大小应确保多数对象在minor gc中回收,避免过早晋升。metaspace需设上限防oom,-xss影响线程数与栈深度平衡,直接内存和jit缓存也需监控。调优应基于监控数据迭代优化,启用gc日志和堆转储是关键。

常用的jvm性能调优参数有哪些?(堆大小、垃圾收集器等)

谈及JVM性能调优,我们通常会围绕几个核心参数展开,它们直接决定了应用程序的运行效率和稳定性。最常用的无疑是堆内存大小(-Xms和-Xmx),它定义了JVM可用的最大和最小内存。其次,垃圾收集器(GC)的选择是另一个关键点,比如G1GC、ParallelGC、ZGC或ShenandoahGC,它们各有侧重,影响着应用的吞吐量和响应延迟。此外,新生代大小(-Xmn或-XX:NewRatio)元空间大小(-XX:MaxMetaspaceSize)以及线程栈大小(-Xss)也是我们不容忽视的调优对象。

解决方案

要系统地进行JVM性能调优,我们得从以下几个维度入手,并结合实际的应用场景和监控数据进行迭代优化。

首先是堆内存的配置

-Xms
用于设置JVM启动时分配的初始堆内存,
-Xmx
则设定了JVM可使用的最大堆内存。一个常见的最佳实践是将这两个值设为相等,即
-Xms<size> -Xmx<size>
。这样做的好处是避免了JVM在运行时动态扩展或收缩堆内存,从而减少了潜在的GC开销和内存抖动。选择合适的大小至关重要:太小会导致频繁的Full GC甚至OutOfMemoryError(OOM),而过大则可能造成物理内存不足,导致操作系统频繁进行内存交换(Swap),严重拖慢应用。我个人经验是,对于大多数服务器应用,可以从物理内存的1/4到1/2开始尝试,然后通过监控工具(如JConsole, VisualVM, Grafana结合JMX exporter)观察GC行为和内存使用情况来微调。

接着是垃圾收集器的选择与配置。这是性能调优中最为复杂也最能体现功力的一环。

  • Parallel GC (
    -XX:+UseParallelGC
    ):注重吞吐量,适合那些可以接受较长GC停顿时间,但希望整体处理能力更强的批处理应用。在Java 8及以前,它通常是默认的服务器端GC。
  • CMS GC (
    -XX:+UseConcMarkSweepGC
    ):追求低停顿,大部分GC工作与应用线程并发执行,但会有碎片化问题和浮动垃圾。虽然在Java 9后被标记为废弃,但理解其设计思想对理解后续GC仍有帮助。
  • G1 GC (
    -XX:+UseG1GC
    ):Java 9及以后版本的默认GC。它将堆划分为多个区域,目标是实现可预测的GC停顿时间。G1通过收集收益最高(Garbage-First)的区域来减少GC时间,是一个非常均衡的选择,适用于大多数中大型应用。
  • ZGC (
    -XX:+UseZGC
    ) 和 Shenandoah GC (
    -XX:+UseShenandoahGC
    ):这两个是针对超大堆(TB级别)和极低停顿时间(亚毫秒级)场景设计的GC。它们通过复杂的着色指针和读屏障技术,将大部分GC工作与应用线程并发执行,停顿时间几乎与堆大小无关。如果你的应用对延迟非常敏感,并且有足够的内存资源,可以考虑它们。

选择GC时,我通常会先从G1开始,因为它在平衡吞吐量和延迟方面做得很好。如果G1无法满足低延迟要求,或者堆内存特别巨大,我才会考虑ZGC或Shenandoah。

此外,新生代的大小也很关键。新生代用于存放新创建的对象。

-Xmn<size>
直接设置新生代大小,或者通过
-XX:NewRatio=<ratio>
设置老年代与新生代的比例(例如
NewRatio=2
表示老年代是新生代的2倍)。合理的新生代大小可以减少Minor GC的频率,但如果过大,则可能导致Minor GC时间过长。我倾向于让新生代足够大,以容纳大部分短生命周期的对象,这样它们在Minor GC中就能被回收,避免进入老年代。

JVM堆内存如何合理设置,避免性能瓶颈?

合理设置JVM堆内存,是避免应用性能瓶颈的基石。这里面有一些经验之谈和技术考量。首先,我们得清楚,堆内存不是越大越好。一个过大的堆可能导致Full GC的周期拉长,一旦发生,停顿时间会非常可观,对用户体验造成严重影响。同时,如果堆内存超过了物理内存,操作系统会开始使用硬盘进行内存交换(Swap),这将导致性能急剧下降,比任何GC问题都更致命。

那么,如何“合理”呢?这通常是一个迭代和观察的过程。

  1. 了解应用特性: 你的应用是内存密集型吗?会创建大量临时对象吗?还是长期持有大量数据?例如,一个批处理应用可能需要较大的堆来处理数据,而一个实时交易系统可能更注重低延迟,不希望堆过大导致GC停顿。
  2. 基线设置: 通常,我会将
    -Xms
    -Xmx
    设置为相等,这避免了JVM在运行时调整堆大小带来的额外开销。初始值可以从物理内存的25%到50%开始尝试。例如,一台16GB内存的服务器,可以尝试
    -Xms8g -Xmx8g
  3. 监控与分析: 这是最关键的一步。使用JMX工具(如JConsole, VisualVM)、GC日志分析工具(如GCViewer, gceasy.io)或APM工具(如SkyWalking, Pinpoint)来持续监控以下指标:
    • 堆内存使用率: 观察堆内存的峰值和平均使用情况。如果长期接近最大值,说明堆可能偏小。
    • GC频率和停顿时间: Minor GC是否过于频繁?Full GC是否发生?停顿时间是否在可接受范围内?
    • 晋升到老年代的对象数量: 如果新生代对象频繁晋升到老年代,可能需要调整新生代大小或优化代码。
  4. 迭代优化: 根据监控数据,逐步调整堆大小。如果OOM频繁发生,或者Full GC过于频繁,尝试增加堆内存。如果发现堆内存利用率很低,且GC表现良好,可以适当减小堆内存,为其他服务或系统预留资源。

一个常见的陷阱是,为了避免OOM,直接把堆设置得非常大。我见过很多案例,应用实际只用了2GB内存,却配置了32GB的堆,结果是浪费资源不说,一旦发生Full GC,那将是灾难性的停顿。所以,平衡是艺术,数据是依据。

不同的垃圾收集器(GC)各有什么特点,我该如何选择?

垃圾收集器是JVM的“心脏”,它的选择直接影响着应用的响应速度和吞吐量。理解它们各自的特点,才能做出明智的决策。

  • Serial GC (

    -XX:+UseSerialGC
    )

    • 特点: 单线程执行所有GC工作,在GC时会暂停所有应用线程(Stop-The-World, STW)。
    • 适用场景: 内存较小(几十到几百MB),CPU核数较少,或客户端应用。它的优势在于简单高效,没有线程协调的开销。
    • 选择理由: 你的应用是桌面程序,或者部署在资源极其有限的微服务实例上,且对GC停顿不敏感。
  • Parallel GC (

    -XX:+UseParallelGC
    )

    Memo AI
    Memo AI

    AI音视频转文字及字幕翻译工具

    下载
    • 特点: 多线程执行Young/Old GC,同样是STW,但利用多核CPU并行处理,旨在提高吞吐量。
    • 适用场景: 后台批处理、数据分析等对吞吐量要求高,但对单次GC停顿时间不那么敏感的场景。
    • 选择理由: 你的应用是计算密集型,可以接受秒级甚至更长的GC停顿,但希望在单位时间内处理更多的数据。
  • CMS GC (

    -XX:+UseConcMarkSweepGC
    )

    • 特点: 旨在降低GC停顿时间,大部分GC工作与应用线程并发执行。它分多个阶段,其中只有初始标记和重新标记阶段是STW的。
    • 适用场景: 对响应时间敏感的Web应用或在线服务。
    • 选择理由: 你的应用需要较低的GC停顿,但你又不想升级到更高版本的JVM使用G1或更先进的GC。需要注意的是,CMS可能会产生内存碎片,并且在并发阶段仍可能出现浮动垃圾导致Full GC。
  • G1 GC (

    -XX:+UseG1GC
    )

    • 特点: 分区(Region)化内存管理,可预测的GC停顿时间。它将堆划分为多个大小相等的区域,并根据用户设定的目标停顿时间,优先回收垃圾最多的区域。
    • 适用场景: 大多数中大型应用,尤其是那些需要平衡吞吐量和低延迟的应用。它能很好地处理大内存堆。
    • 选择理由: 你的应用是现代的Web服务、微服务,对GC停顿有一定要求,且堆内存可能较大。G1是Java 9+的默认GC,通常是一个很好的起点。
  • ZGC (

    -XX:+UseZGC
    ) / Shenandoah GC (
    -XX:+UseShenandoahGC
    )

    • 特点: 极致的低停顿,停顿时间与堆大小无关,通常在亚毫秒级。它们通过着色指针、读屏障等高级技术实现几乎与应用线程并发的GC。
    • 适用场景: 对延迟要求极其严苛的场景,如高频交易系统、实时数据处理、超大规模内存数据库等。
    • 选择理由: 你的应用对延迟的容忍度极低,即使是几毫秒的停顿都无法接受,并且拥有足够的CPU和内存资源来支持这些GC的额外开销。

我个人选择的思路: 对于新项目或升级项目,我通常会从 G1 GC 开始。它在大多数情况下表现出色,兼顾了吞吐量和低延迟。如果G1无法满足特定的低延迟需求,并且应用运行在较新的JVM版本上,我会考虑 ZGC 或 Shenandoah。对于一些老旧的系统,如果无法升级JVM,那么 Parallel GC 可能是提高吞吐量的选择,而 CMS 则是降低停顿的方案。但无论选择哪个,都离不开持续的监控和调优。

除了堆和GC,还有哪些容易被忽视的JVM调优参数?

除了堆内存和垃圾收集器,JVM还有一些参数,虽然不那么“显眼”,但在特定场景下,它们对应用性能和稳定性有着举足轻重的影响。有时候,一个细微的调整就能解决一个棘手的生产问题。

  1. Metaspace 大小 (

    -XX:MaxMetaspaceSize
    ,
    -XX:MetaspaceSize
    )

    • 作用: Metaspace用于存储类的元数据,如类定义、方法字节码等。它取代了PermGen(永久代)。
    • 为什么容易忽视: 默认情况下,Metaspace是根据需要自动扩展的,但如果加载的类太多(比如动态生成类、大量使用框架),或者类加载器泄漏,Metaspace可能会耗尽,导致OOM。
    • 调优:
      -XX:MaxMetaspaceSize
      设置最大值,避免无限制增长。
      -XX:MetaspaceSize
      设置初始值。如果你的应用需要加载大量类或使用动态代理,监控Metaspace使用情况是必要的。我通常会用
      jcmd <pid> GC.class_histogram
      来查看当前加载的类信息。
  2. 线程栈大小 (

    -Xss<size>
    )

    • 作用: 每个Java线程都有自己的栈空间,用于存储方法调用、局部变量等。
    • 为什么容易忽视: 默认值通常是1MB(Linux)或256KB(Windows),对于大多数应用足够。但如果应用有大量递归调用,或者创建了非常多的线程,可能会导致
      StackOverflowError
      或耗尽系统内存。
    • 调优: 减小
      -Xss
      可以让系统创建更多的线程,但增加了
      StackOverflowError
      的风险。增大
      -Xss
      可以处理更深的调用栈,但会减少系统可创建的线程数。这是一个平衡问题,需要根据应用的线程模型和调用深度来权衡。
  3. JIT 编译器相关参数

    • 作用: JIT(Just-In-Time)编译器将热点代码编译成机器码,显著提升执行效率。
    • 为什么容易忽视: 大部分情况下,JVM的默认JIT行为已经很优秀。
    • 调优:
      • -XX:+TieredCompilation
        :启用分层编译,通常默认开启。它结合了客户端编译器(C1)和服务器编译器(C2),先用C1快速编译,再用C2进行深度优化,平衡了启动速度和峰值性能。
      • -XX:CompileThreshold=<count>
        :设置方法被调用多少次后才会被JIT编译。对于某些需要快速启动或预热的应用,调整这个值可能有帮助。
      • -XX:ReservedCodeCacheSize=<size>
        :设置JIT编译代码的缓存区大小。如果这个区域满了,JIT就无法继续编译,只能解释执行,性能会下降。
  4. 直接内存(Direct Memory)

    • 作用: Java NIO(New I/O)和一些第三方库(如Netty)会使用直接内存,它不受JVM堆管理,但受限于物理内存。
    • 为什么容易忽视: 它不属于Java堆,所以
      -Xmx
      无法控制它。但如果直接内存使用过多,同样会导致OOM,通常表现为
      OutOfMemoryError: Direct buffer memory
    • 调优:
      -XX:MaxDirectMemorySize=<size>
      可以显式设置最大直接内存。默认值通常与
      -Xmx
      相同。如果应用大量使用NIO或类似技术,需要监控其使用情况。
  5. GC 日志配置

    • 作用: 记录GC事件的详细信息,是分析GC行为、诊断性能问题的关键数据。
    • 为什么容易忽视: 很多人只知道设置GC参数,却忘了收集GC日志。没有日志,调优就是盲人摸象。
    • 调优:
      • Java 9+:
        -Xlog:gc*=info:file=<path>/gc.log:time,uptime,pid,level,tags
        提供了非常灵活的日志配置。
      • Java 8及更早版本:
        -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:<path>/gc.log
      • 重要性: 启用GC日志是生产环境的必备配置,它是我们理解JVM行为的“眼睛”。
  6. 堆转储(Heap Dump)配置

    • 作用: 在OOM发生时自动生成堆内存快照,用于事后分析内存泄漏。
    • 为什么容易忽视: 只有在出问题时才想起,但往往那时已经错过了最佳收集时机。
    • 调优:
      -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<path>/heapdump.hprof
      。这个参数至关重要,能帮助我们快速定位内存泄漏的根源。

这些参数的调优并非一蹴而就,它需要我们对应用有深刻的理解,并结合持续的监控和数据分析,才能找到最适合的配置。有时候,解决一个性能问题,并不在于把某个参数调到极致,而在于发现那个被忽视的“木桶短板”。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

443

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

605

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

764

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

376

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

30

2026.01.21

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.5万人学习

Git 教程
Git 教程

共21课时 | 4.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号