JVM 调优理论
前言
关于性能优化
The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming. — Donald Ervin Knuth
真正的问题是,程序员在错误的地方和错误的时间花了太多的时间担心效率问题;过早的优化是编程中所有(或者至少是大部分)罪恶的根源。
什么是 JVM 调优?
通过 JVM 参数的调整,优化 JVM 对于内存的管理,Java 应用性能提升的最后手段
为什么是最后手段?因为调整 JVM 的投入产出比往往低于对于应用本身的优化
为什么要进行 JVM 调优?
内存宝贵,性能重要,其他性能优化手段都已经用上,但仍未满足性能需求
知识补充
常见应用程序模型抽象
-
任务视角:任务执行靠 CPU,多线程视角下的应用程序模型
- CPU 密集型:CPU 忙碌,即使引入多线程也要等待,不利于提高计算效率,耗时可能不降反升
- IO 密集型:CPU 空闲,引入多线程有助于接受更多的并发请求,有助于提升吞吐量,进而降低耗时
-
对象视角:对象使用消耗空间,根据对象特点动态分析 GC 视角下的应用程序模型
-
极致新生代(只创建新对象):新生代空间 ↑,GC 频率 ↑
IO 交互型: 互联网上目前大部分的服务都属于该类型,例如分布式 RPC、MQ、HTTP 网关服务等,对内存要求并不大,大部分对象在 TP9999 的时间内都会死亡, Young 区越大越好。
-
极致老年代(极限单例模式):老年代空间 ↑,GC 频率 ↓
MEM 计算型: 主要是分布式数据计算 Hadoop,分布式存储 HBase、Cassandra,自建的分布式缓存等,对内存要求高,对象存活时间长,Old 区越大越好。
-
-
供需视角:根据应用特点(垃圾生成速率和持久性)静态分析 GC 视角下的应用程序模型
- 垃圾少:Serial GC,额外内存占用少
- 垃圾多:看硬件环境限制
硬件性能 ↓ ,选用:G1 > CMS GC > Parallel GC > Serial GC,从左到右对应的响应时间 ↑
JVM 常用参数
参数分类
知识补充:JVM 其实并不唯一,只要按照 Java 虚拟机规范,甚至可以自研 JVM,只不过现在最常用的还是Oracle 提供的官方实现(HotSpot JVM)
- 标准参数(-),所有的 JVM 实现都必须实现这些参数的功能,而且向后兼容
- 用法:
java -help
查看当前机器所有java的标准参数列表
- 用法:
- 非标准参数(-X),默认 JVM 实现这些参数的功能,但是并不保证所有 JVM 实现都满足,且不保证向后兼容
- 用法:
java -X
查看当前JVM支持的所有非标准参数列表(注意:X 要大写)
- 用法:
- 非 Stable 参数(-XX),此类参数各个 JVM 实现会有所不同,将来可能会随时取消,需要慎重使用
- 分类
- 性能参数(Performance Options):用于 JVM 的性能调优和内存分配控制,如初始化内存大小的设置
- 行为参数(Behavioral Options):用于改变 JVM 的基础行为,如 GC 的方式和算法的选择
- 调试参数(Debugging Options):用于监控、打印、输出等 JVM 参数,用于显示 JVM 更加详细的信息
- 用法
-XX:+<option>
启用选项-XX:-<option>
不启用选项-XX:<option>=<number>
给选项设置一个数字类型值,可跟单位,例如 32k, 1024m, 2g-XX:<option>=<string>
给选项设置一个字符串值,例如-XX:HeapDumpPath=./dump.core
- 分类
参数映射关系
常用参数列表
参数名称 | 示例用法 | 参数作用 |
---|---|---|
-Xms | -Xms256m | 设置 JVM 堆的初始大小 |
-Xmx | -Xmx512m | 设置 JVM 堆的最大大小 |
-Xss | -Xss256k | 设置每个线程的栈大小 |
-XX:PermSize | -XX:PermSize=128m | 设置永久代的初始大小(在 JDK8 及以上版本,该参数已被废弃) |
-XX:MaxPermSize | -XX:MaxPermSize=256m | 设置永久代的最大大小(在 JDK8 及以上版本,该参数已被废弃) |
-XX:MetaspaceSize | -XX:MetaspaceSize=128m | 设置元空间的初始大小(在 JDK8 及以上版本,取代了 PermGen 和 MaxPermSize) |
-XX:MaxMetaspaceSize | -XX:MaxMetaspaceSize=256m | 设置元空间的最大大小(在 JDK8 及以上版本,取代了 PermGen 和 MaxPermSize) |
-XX:SurvivorRatio | -XX:SurvivorRatio=8 | 设置新生代中 Eden 区与 Survivor 区的大小比例 |
-XX:NewRatio | -XX:NewRatio=2 | 设置新生代和老年代的大小比例 |
-XX:MaxTenuringThreshold | -XX:MaxTenuringThreshold=15 | 设置对象在新生代中经过多少次垃圾回收后进入老年代 |
-XX:G1HeapRegionSize | -XX:G1HeapRegionSize=1m | 设置 G1 垃圾回收器的堆区域大小,该参数影响堆中对象的分配及垃圾回收的速度 |
-XX:+UseParallelGC | -XX:+UseParallelGC | 启用并行垃圾回收器,该垃圾回收器采用多个线程同时进行垃圾回收,适用于多核服务器 |
-XX:+UseConcMarkSweepGC | -XX:+UseConcMarkSweepGC | 启用并发标记-清除垃圾回收器,该垃圾回收器在垃圾回收时不会暂停整个应用程序的执行,适用于服务器环境 |
-XX:+UseG1GC | -XX:+UseG1GC | 启用 G1 垃圾回收器,该垃圾回收器是一种新的垃圾回收器,适用于大内存、多核的服务器环境 |
示例
idea.vmoptions
-Xmx8192m
-XX:ReservedCodeCacheSize=512m
-Xms128m
-XX:+UseG1GC
-XX:SoftRefLRUPolicyMSPerMB=50
-XX:CICompilerCount=2
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-ea
-Dsun.io.useCanonCaches=false
-Djdk.http.auth.tunneling.disabledSchemes=""
-Djdk.attach.allowAttachSelf=true
-Djdk.module.illegalAccess.silent=true
-Dkotlinx.coroutines.debug=off
-Dsplash=true
-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log
-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof
-Xmx8192m
:设置Java堆的最大内存大小为8192MB。-XX:ReservedCodeCacheSize=512m
:设置保留代码缓存的大小为512MB。-Xms128m
:设置Java堆的初始内存大小为128MB。-XX:+UseG1GC
:启用G1垃圾回收器。-XX:SoftRefLRUPolicyMSPerMB=50
:设置软引用在内存不足时的最大存活时间。-XX:CICompilerCount=2
:设置并行编译器线程数为2。-XX:+HeapDumpOnOutOfMemoryError
:在内存溢出错误发生时生成堆转储文件。-XX:-OmitStackTraceInFastThrow
:不在快速抛出异常的情况下省略堆栈跟踪。-ea
:启用断言。-Dsun.io.useCanonCaches=false
:禁用Java IO规范的规范化缓存。-Djdk.http.auth.tunneling.disabledSchemes=""
:启用所有的HTTP身份验证协议。-Djdk.attach.allowAttachSelf=true
:允许进程自我附加。-Djdk.module.illegalAccess.silent=true
:静默模式下不显示非法访问模块警告。-Dkotlinx.coroutines.debug=off
:关闭Kotlin协程的调试模式。-Dsplash=true
:启用启动时的启动画面。-XX:ErrorFile=$USER_HOME/java_error_in_idea_%p.log
:将错误日志写入到用户主目录下的java_error_in_idea_进程ID.log文件中。-XX:HeapDumpPath=$USER_HOME/java_error_in_idea.hprof
:将堆转储文件写入到用户主目录下的java_error_in_idea.hprof文件中(用于内存溢出错误时)。
JDK 常用工具
工具名称 | 示例用法 | 工具功能 |
---|---|---|
jstat | jstat -<option> <pid> [<interval> [<count>]] |
jstat 用于监视 JVM 的各种统计信息,例如垃圾回收信息、类加载信息、JIT 编译信息等。 |
jmap | jmap [-<option>] <pid> |
jmap 用于生成 JVM 的堆转储快照(heap dump),可以用于分析内存泄漏问题。 |
jstack | jstack [-l] <pid> |
jstack 用于生成 Java 进程的线程转储快照(thread dump),可以用于分析线程死锁、死循环等问题。 |
jconsole | jconsole |
jconsole 是 JDK 提供的图形化监控工具,可以实时查看 JVM 的各种运行信息,例如内存使用情况、线程状态、GC 情况等。 |
jcmd | jcmd <pid> <command> [<arguments>] |
jcmd 可以执行一些诊断命令,例如 GC 相关操作、线程分析、JIT 编译等。 |
jvisualvm | jvisualvm |
jvisualvm 是 JDK 提供的增强型图形化监控工具,集成了 jconsole、jstack、jmap 等多个工具,并提供了插件支持。 JDK 8 之后不再集成,需要额外下载 |
jmc | jmc |
jmc 是 JDK 提供的 Java Mission Control 工具,提供了全面的性能分析、故障诊断和优化调整功能,适用于生产环境的性能监控。 不一定集成,可能需要额外下载 |
垃圾回收器评价指标
- 内存回收效率:评估 GC 回收器的内存回收能力,即回收多少内存和回收多快。这可以通过监测内存回收的频率和时间来评估。
- 暂停时间:评估 GC 回收器对应用程序暂停的影响。较短的暂停时间可以提高应用程序的响应能力和用户体验。
- 吞吐量:评估 GC 回收器对应用程序可用时间和执行吞吐量的影响。较高的吞吐量表示应用程序能够在较短的时间内执行更多的工作。
- 内存占用:评估 GC 回收器的内存占用情况。较低的内存占用可以提高系统整体的资源利用率。
- 垃圾碎片:评估 GC 回收器在回收内存时会产生多少碎片。较少的垃圾碎片可以减少内存碎片化,提高内存使用效率。
常见垃圾回收器
-
Serial(串行回收器):
- 设计理念:串行回收器使用单个线程进行垃圾回收,适用于低内存和单核处理器的环境。
- 内存回收效率:较低,只能利用单个线程进行垃圾回收。
- 暂停时间:较长,由于只有单个线程执行垃圾回收,会导致暂停时间较长。
- 吞吐量:相对较低,因为垃圾回收过程会占用较长时间。
- 内存占用:相对较低。
- 垃圾碎片:可能会产生较多的垃圾碎片。
-
Parallel(并行回收器):
补充:ParNew 垃圾回收器
ParNew 与 Parallel 并没有本质上的区别,其主要是为了配合 CSM 的垃圾收集而提供的年轻代的垃圾收集器,其只有年轻代的收集版本,垃圾收集上与 Parallel 相同。
目前仅有 Serial 和 ParNew 可与 CSM 进行配合垃圾收集。
- 设计理念:并行回收器使用多个线程并行执行垃圾回收,适用于多核处理器的环境。
- 内存回收效率:较高,可以利用多个线程并行执行垃圾回收。
- 暂停时间:较长,尽管有多个线程并行执行垃圾回收,但仍然需要暂停应用程序的执行。
- 吞吐量:较高,相对于串行回收器具有更高的吞吐量。
- 内存占用:相对较高,需要多个线程执行垃圾回收,可能会占用更多的内存资源。
- 垃圾碎片:可能会产生较多的垃圾碎片。
-
CMS(Concurrent Mark Sweep,并发标记清除回收器):
- 设计理念:CMS回收器通过并发执行标记和清除操作,尽量减少应用程序的暂停时间。
- 内存回收效率:较高,通过并发执行来减少应用程序的暂停时间。
- 暂停时间:较短,CMS回收器通过并发执行垃圾回收的阶段,将应用程序的暂停时间控制在较短的范围内。
- 吞吐量:相对较高,因为暂停时间较短,应用程序可以更快地回到执行状态。
- 内存占用:较高,CMS回收器需要为维护并发执行所需的数据结构而占用一部分内存。
- 垃圾碎片:可能会产生较多的垃圾碎片。
-
G1(Garbage-First,垃圾优先回收器):
- 设计理念:G1回收器将堆内存划分为多个区域(Region),根据垃圾产生的情况进行回收,以最小化暂停时间。
- 内存回收效率:较高,G1回收器可以根据垃圾产生的情况选择合适的区域进行回收,提高内存回收效率。
- 暂停时间:较短,G1回收器可以在不暂停整个应用程序的情况下并发执行部分垃圾回收操作。
- 吞吐量:相对较高,G1回收器通过并发执行和自适应的垃圾回收策略,可以在不同的情况下提供较高的吞吐量。
- 内存占用:相对较高,G1回收器需要额外的内存来管理区域和维护相关数据结构。
- 垃圾碎片:相对较低,G1回收器通过压缩回收和空闲区域整理等策略,可以减少垃圾碎片的产生。
回收器名称 | 设计理念 | 内存回收效率 | 暂停时间 | 吞吐量 | 内存占用 | 垃圾碎片 |
---|---|---|---|---|---|---|
Serial GC | 单线程 | 低 | 长 | 低 | 低 | 高 |
Parallel GC | 多线程 | 高 | 中等 | 高 | 中等 | 中等 |
CMS GC | 并发标记清除 | 中等 | 短 | 高 | 高 | 高 |
G1 GC | 分代、区域化 | 高 | 短 | 高 | 高 | 低 |
评价整理
回收器名称 | 内存回收效率 | 暂停时间 | 吞吐量 | 内存占用 | 垃圾碎片 |
---|---|---|---|---|---|
Serial GC |
标签:回收,XX,调优,GC,内存,JVM,实验,垃圾
From: https://www.cnblogs.com/ba11ooner/p/17806880.html
相关文章
|