科普文:一文搞懂jvm实战(五)通用JVM参数配置
我们先看看jvm参数,通过jvm参数来配置jvm内存大小(堆、栈、元数据区、直接内存)和垃圾回收器JVM 参数主要有 3 类:标准参数,非标准参数,高级参数。标准参数所有的 Java 虚拟机都支持,用于常见操作,例如:检查 Java 版本,查看 java 命令的用法等,标准参数以“-”开头。-version :查看 Java 版本-help :查看 java 命令的使用帮助非标准参数不能保证所有
JVM参数概叙
前面我们介绍了jvm,关于jvm实战,将分成两部分:
- 通用jvm参数:设jvm内存和垃圾收集器
- jvm调优:带上场景要求的调优设置
我们先看看jvm参数,通过jvm参数来配置jvm内存大小(堆、栈、元数据区、直接内存)和垃圾回收器
JVM 参数主要有 3 类:标准参数,非标准参数,高级参数。
1、标准参数(Standard Options)
标准参数所有的 Java 虚拟机都支持,用于常见操作,例如:检查 Java 版本,查看 java 命令的用法等,标准参数以“-”开头。
-version :查看 Java 版本
-help :查看 java 命令的使用帮助
2、非标准参数(Non-Standard Options)
非标准参数不能保证所有 Java 虚拟机都支持它们,不同的 JDK 版本可能会发生变化,这些参数以“-X”开头。
-Xmixed:混合模式执行 (默认)
-Xint:仅解释模式执行
-Xms<size>:设置堆的初始大小
-Xmx<size>:设置内存分配池的最大大小
-Xss<size>:设置线程堆栈大小
CMD 里运行 java -X
命令,可以显示所有可用 -X 参数的说明。
3、高级参数(Advanced Options)
开发人员使用最多的参数,用于 JVM 调优和 debug,不同的 JDK 版本可能会发生变化,这些参数以 “-XX” 开头。
“-XX” 参数有 2 种类型:Boolean 类型和需要参数的类型。
Boolean 类型:用于启用默认情况下禁用的功能,或者禁用默认情况下启用的功能,此类选项不需要参数。
格式:-XX:[+-] <OptionName>, “+” 或 “-” 表示启用或者禁用 OptionName 属性。
-XX:+UseConcMarkSweepGC 表示启用 CMS 垃圾收集器
-XX:+UseG1GC 表示启用 G1 垃圾收集器
-XX:+PrintCommandLineFlags 表示启用打印 JVM 设定的值,例如堆空间大小和选定的垃圾收集器
需要指定参数值的类型:用于指定某个参数为某个值。
格式:-XX:<OptionName>=<value>,表示 OptionName 属性的值是 value。
-XX:ThreadStackSize=size 设置线程堆栈大小(以字节为单位),字母“k”或“K”表示千字节,“m”或“M”表示兆字节,“g”或“G”表示千兆字节。“-XX:ThreadStackSize ”等效于 “-Xss”。
-XX:InitialHeapSize=size 设置内存分配池的初始大小(以字节为单位),此值必须为 0 或 1024 的倍数且大于 1 MB,“-XX:InitialHeapSize”等效于 “-Xms”。
-XX:MaxHeapSize=size 设置内存分配池的最大大小(以字节为单位),此值必须是 1024 的倍数且大于 2 MB,“-XX:MaxHeapSize ”等效于 “-Xmx”。
-XX:MaxGCPauseMillis=time 设置最大 GC 暂停时间的目标(以毫秒为单位)
4、以下是一些常见的JVM参数和配置选项:
-classpath:指定类路径,可以包括多个目录和JAR文件。
-verbose:启动JVM时输出详细信息,包括类加载、内存分配和线程启动等。
-version:显示JVM版本信息。
-showversion:启动JVM时显示版本信息。
-X:使用非标准选项启动JVM,可以指定各种参数和配置选项。
-Xmx:设置JVM最大堆内存大小,例如-Xmx2G表示最大堆内存为2GB。
-Xms:设置JVM初始堆内存大小,例如-Xms512M表示初始堆内存为512MB。
-XX:PermSize 和 -XX:MaxPermSize:设置永久代(PermGen)的初始大小和最大大小。
-XX:+UseConcMarkSweepGC:使用并发标记清除(CMS)垃圾回收器。
-XX:+UseParallelGC:使用并行垃圾回收器。
-XX:+PrintGC:启动垃圾回收时输出垃圾回收信息。
-XX:+PrintGCDetails:启动垃圾回收时输出详细的垃圾回收信息。
-Xloggc:指定垃圾回收日志文件的路径和名称。
-XX:ParallelGCThreads:指定并行垃圾回收线程数。
-XX:MaxDirectMemorySize:设置直接内存的最大大小。
这些参数和配置选项可以用来调整JVM 的行为和性能,以便更好地适应不同的应用场景和硬件环境。
JDK 8 的参数官方链接:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDCEGG
大家可以自行研究。
JVM内存参数设置
以JDK1.8为例,目前大部分环境还是jdk1.8.
// 设置JVM使Server模式,特点是启动速度较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的JDK环境下默认启用该模式。
-server
##堆内存
// 设置最大堆内存,默认是物理内存的1/4,内存的单位可以是m g,并且不区分大小写
-Xmx2g 或者 -XX:MaxHeapSize=2048m
// 设置初始值堆内存,默认是物理内存的1/64,内存的单位可以是m g,并且不区分大小写
-Xms2g 或者 -XX:InitialHeapSize=2048m
// 设置年轻代内存大小,默认和老年代1\2,-XX:NewSize初始化年轻代大小 -XX:MaxNewSize最大年轻代大小
-Xmn1g 或者 -XX:NewSize=1g -XX:MaxNewSize=1g
// 年轻代占用堆比例(如果有配置-Xmn,那么会以-Xmn配置为准)
// 默认 -XX:NewRatio=2新生代占1,老年代占2,年轻代占整个堆的1/3
// 假如 -XX:NewRatio=4新生代占1,老年代占4,年轻代占整个堆的1/5 NewRatio值就是设置老年代的占比,剩下的1给新生代
-XX:NewRatio=2
// 用来设置新生代中eden空间和from/to空间的比例.含义:-设置为8代表 eden使用80%的新生代内存 from和to各用10%,默认为8
-XX:SurvivorRatio=8
// 禁用Survivor区自适应策略默认是开启的,如果不关闭这个配置新生代eden区和s0 s1区会在gc后自动调整大小,如果设置了-XX:SurvivorRatio也只有在没有GC之前有效只要GC后就会重新动态计算
-XX:-UseAdaptiveSizePolicy
// 扩张堆内存的时机
// 堆内存使用率大于70时扩张堆内存,如果最大堆内存=初始堆内存时该参数无效,默认值70
-XX:MaxHeapFreeRatio=70
// 缩小堆内存的时机
// 堆内存使用率小于40时缩减堆内存,如果最大堆内存=初始堆内存时该参数无效,默认值40
-XX:MinHeapFreeRatio=40
// 字符串常量池hash桶大小 类似于HashTable,最小值1009 默认60013 不可动态扩容
-XX:StringTableSize=60013
##元空间内存
// 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小,如果超过这个值会内存溢出。
-XX:MaxMetaspaceSize=256m
// 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M,达到该值就会触发full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超过-XX:MaxMetaspaceSize(如果设置了的话) 的情况下, 适当提高该值。这个跟早期jdk版本的-XX:PermSize参数意思不一样,-XX:PermSize代表永久代的初始容量。
// 触发一次元空间Full GC后就会重新计算该值,建议设置成和最大内存一致
-XX:MetaspaceSize=256m
##直接内存
// 设置直接内存大小,NIO(Non-blocking I/O)中通过ByteBuffer等对象分配的堆外内存
// 默认情况下,直接内存的大小可能会与Java堆的最大值 (-Xmx) 相同
-XX:MaxDirectMemorySize=512m
##栈内存
// 设置每个线程的堆栈大小 默认是1024k,这个是最大内存并不是开启一个线程马上就会消耗这么多内存
-Xss512k 或者 -XX:ThreadStackSize=512k
JVM垃圾收集器参数设置
1 吞吐量优先的GC典型配置参数
java -server -Xmx4g -Xms4g -Xmn2g –Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
2 响应时间优先的GC典型配置参数
java -server -Xmx4g -Xms4g -Xmn2g –Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:+UseConcMarkSweepGC: 设置年老代为并发收集
-XX:+UseParNewGC: 设置年轻代为并行收集。可与CMS收集同时使用
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片
3.Parallel 和 Parallel Old 常用参数配置
// 调整垃圾回收的时间和总时间的占比 公式 1/(1+ratio) ratio默认是99,100分钟运行时间默认不能超过1分钟的GC时间,ratio一般设置为19
-XX:GCTimeRatio=99
// GC最大暂停毫秒数 默认是200毫秒 和-XX:+GCTimeRatio有冲突,堆内存小回收速度才会快,而-XX:+GCTimeRatio需要保证一定时间内GC时间不能超过一个临界值需要增加内存才能减小GC时间比,需要找到一个两个参数的合理值
-XX:MaxGCPauseMillis=200ms
// 设置垃圾回收线程数量 默认是CUP内核数量
-XX:ParallelGCThreads=4
4.CMS 常用参数配置
// GC最大暂停毫秒数 默认是200毫秒
-XX:MaxGCPauseMillis=200ms
// 为了加快此阶段处理速度,减少停顿时间,可以开启初始标记并行化
-XX:+CMSParallelInitialMarkEnabled
// CMS并行线程数量,并行线程用于执行 CMS 垃圾回收器的并行阶段,如初始标记阶段和重新标记阶段
// 默认值为系统的逻辑处理器数量减1,目的是为了保留一个处理器用于应用程序线程
-XX:ParallelCMSThreads=3
// CMS并发线程数量,并发线程用于执行 CMS 垃圾回收器的并发阶段,如初始标记阶段、并发标记阶段和并发清理阶段。
// 默认值为系统的逻辑处理器数量减1,目的是为了保留一个处理器用于应用程序线程
-XX:ConcGCThreads=3
// 执行CMS的内存占比 percent=80 当我的老年代内存达到80%触发垃圾回收 默认是92% 应为CMS采用标记清除需要给浮动垃圾(在最后一步并发清除时其它没有被标记的垃圾遗留)预留空间
-XX:CMSInitiatingOccupancyFraction=percent
// 该参数需要配合XX:CMSInitiatingOccupancyFraction使用,只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设 定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
-XX:+UseCMSInitiatingOccupancyOnly
// 重新标记阶段前提前进行一次新生代GC,因为重新标记也会判断新生代对象是否引用老年代对象,有些时候新生代对象已经没有被GC root对象引用但是还没有GC时,重新标记会扫描到新生代对象并且保留新生代对象引用的老年代对象,默认关闭false
-XX:CMSScavengeBeforeRemark=true
// 执行完Full GC后对内存空间进行压缩整理 默认开启
-XX:+UseCMSCompactAtFullGollection
// 设置在执行多少次Full GC后对内存空间进行压缩整理 默认0次,只要触发Full GC就会进行内存压缩
-XX:CMSFullGCsBeforeCompaction=0
// 垃圾回收时是否同时卸载不用的class信息,默认关闭
-XX:+CMSClassUnloadingEnabled
5.G1 常用参数配置
// 指定分区大小(1MB~32MB,且必须是2的N次幂),不设置默认会根据堆大小分配
// 堆内存为1G默认1024个1MB分区、堆内存为2G默认2048个1MB分区、堆内存为4G默认2048个2MB分区、堆内存为4G默认2048个2MB分区、堆内存为6G默认6144个1MB分区、堆内存为8G默认2048个4MB分区、以此类推
-XX:G1HeapRegionSize=2m
// 目标暂停时间(默认200ms)
-XX:MaxGCPauseMillis=200ms
// 新生代内存初始空间(默认整堆5%)
// PS: 因为JDK版本问题,在启动时可能会出现 "Error: VM option 'G1NewSizePercent' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."
// 如果出现上述问题,在启动参数中添加-XX:+UnlockExperimentalVMOptions即可
-XX:G1NewSizePercent=5
// 新生代内存最大空间 (默认整堆60%)
-XX:G1MaxNewSizePercent=60
// Survivor区的填充容量(默认50%),Survivor区域里的一批对象(年龄1+年龄2+年龄n的多个 年龄对象)总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代
-XX:TargetSurvivorRatio=50
// 最大年龄阈值(默认15)
-XX:MaxTenuringThreshold=15
// 老年代占用空间达到整堆内存阈值(默认45%),则执行新生代和老年代的混合收集(MixedGC)
-XX:InitiatingHeapOccupancyPercent=45
// region中的存活对象低于这个值时才会回收该region,如果超过这个值,存活对象过多,回收的的意义不大(默认65%)。
-XX:G1MixedGCLiveThresholdPercent=65
// 在一次回收过程中指定做几次筛选回收(默认8次),在最后一个筛选回收阶段可以回收一会,然后暂停回收,恢复系统运行,一会再开始回收,这样可以让系统不至于单次停顿时间过长。
-XX:G1MixedGCCountTarget=8
// gc过程中空出来的region是否充足阈值,在混合回收的时候,对Region回收都是基于复制算法进行的,都是把要回收的Region里的存活对象放入其他Region,然后这个Region中的垃圾对象全部清理掉,这样的话在回收过程就会不断空出来新的Region,一旦空闲出来的Region数量达到了堆内存的5%,此时就会立即停止混合回收,意味着本次混合回收就结束了(默认5%)。
-XX:G1HeapWastePercent=5
dump日志参数设置
## OutOfMemory异常时生成dump文件
// 默认关闭
// 可以通过jinfo -flag [+|-]HeapDumpOnOutOfMemoryError <pid> 或 jinfo -flag HeapDumpOnOutOfMemoryError=<value> <pid> 来动态开启或设置值
-XX:+HeapDumpOnOutOfMemoryError
// 设置文件存储路径
// 当HeapDumpOnOutOfMemoryError开启的时候,dump文件的保存路径,默认为工作目录下的,可以通过配置指定保存路径
-XX:HeapDumpPath=/data/dump/jvm.hprof
## 发生Full GC时生成dump文件
// 在Full GC前dump
-XX:+HeapDumpBeforeFullGC
// 在Full GC后dump
-XX:+HeapDumpAfterFullGC
// 设置Dump保存的路径
-XX:HeapDumpPath=/data/dump/jvm.hprof
GC日志参数设置
// 设置日志目录和日志名称
-Xloggc:/data/logs/gc-%t.log
// 开启滚动生成日志 默认关闭
-XX:+UseGCLogFileRotation
// 滚动GC日志文件数,默认0不滚动,保留最多5个日志文件
-XX:NumberOfGCLogFiles=5
// GC文件滚动大小,需开启UseGCLogFileRotation,每个文件最大为20MB
-XX:GCLogFileSize=20M
// 在进行GC的前后打印出堆的信息
-XX:+PrintHeapAtGC
// 打印新生代晋升详情
-XX:+PrintTenuringDistribution
// 打印字符串常量池堆信息
-XX:+PrintStringTableStatistics
// 打印GC信息
-verbose:gc
// 打印GC详细信息
-XX:+PrintGCDetails
// 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCTimeStamps
// 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintGCDateStamps
// 打印当前JVM参数信息 建议在每个程序中都添加上
-XX:+PrintCommandLineFlags
// 产生GC的原因(默认开启)
-XX:+PrintGCCause
// JVM自身故障导致进程奔溃时,会有一个日志文件生成,它包含了导致crash的重要信息,通过分析文件来查找crash原因
-XX:ErrorFile=/data/logs/jvmerror.log
// JDK1.6开始,默认server模式下开启了这个参数,意为当jvm检测到程序在重复抛一个异常
// 在执行若干次后会将异常吞掉,这里的若干次在jdk1.7测得是20707。即执行20707次后,stackTrace 长度会为0。有时这不利于我们排错,通过指定OmitStackTraceInFastThrow,可禁用这功能
-XX:-OmitStackTraceInFastThrow
内存溢出排查
一般来说内存溢出主要分为以下几类:
堆溢出(java.lang.OutOfMemoryError: Java heap space) 栈深度不够( java.lang.StackOverflowError) 栈线程数不够(java.lang.OutOfMemoryError: unable to create new native thread) 元空间溢出(java.lang.OutOfMemoryError: Metaspace)
参考之前的文章
Java web应用性能分析之【6种OOM模拟】_java 模拟oom-CSDN博客
Java web应用性能分析之【OOM监控分析之Allocation Failure】_java allocation failure-CSDN博客
Java web应用性能分析之【6种OOM监控和分析】_java oom 监控-CSDN博客
Java web应用性能分析之【java进程问题分析定位】-CSDN博客
Java web应用性能分析之【jvisualvm远程连接云服务器】_java visualvm如何远程连接阿里云服务器-CSDN博客
Java web应用性能分析之【java进程问题分析工具】_java 进程分析-CSDN博客
Java web应用性能分析之【java进程问题分析概叙】-CSDN博客
切记上图,OOM是错误ERROR,不是异常Exption。
1、元空间溢出(java.lang.OutOfMemoryError: Metaspace)
Metaspace元空间主要是存储类的元数据信息,各种类描述信息,比如类名、属性、方法、访问限制等,按照一定的结构存储在Metaspace里。 一般来说,元空间大小是固定不变的。在出现溢出后,首先通过命令或监控工具(如下图)查看元空间大小,再检查是否-XX:MaxMetaspaceSize配置太小导致。
如果发现元空间大小是持续上涨的,则需要检查代码是否存在大量的反射类加载、动态代理生成的类加载等导致。可以通过-XX:+TraceClassLoading -XX:+TraceClassUnloading记录下类的加载和卸载情况,反推具体问题代码。
2、栈深度不够(java.lang.StackOverflowError)
引发StackOverFlowError的常见原因有:
- 无限循环递归调用
- 同一时间执行大量方法,资源耗尽
- 方法中声明大量局部变量
- 其它消耗栈资源的方法
- xss配置太小导致
代码语言:javascript
复制
/**
* VM Args: -Xss128k
*/
public class JavaStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) {
JavaStackSOF oom = new JavaStackSOF();
try{
oom.stackLeak();
}catch(Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
代码语言:javascript
复制
stack length:2101
Exception in thread "main" java.lang.StackOverflowError
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:13)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
at com.sandy.jvm.chapter02.JavaStackSOF.stackLeak(JavaStackSOF.java:14)
3、栈线程数不够(java.lang.OutOfMemoryError: unable to create new native thread)
这类错误目前在生成系统只遇到过一次,原因是:linux系统中非root用户默认创建线程数最多是1024。解决办法是修改文件:/etc/security/limits.d/90-nproc.conf 还有一种情况是-xss配置太大,那么操作系统可创建的最大线程数太小导致,一般除非误操作是不会出现此问题的。
4、堆溢出(java.lang.OutOfMemoryError: Java heap space)
堆溢出是常见也是最复杂的一种情况。导致堆溢出可能的情况有:
- 堆内存配置太小
- 超出预期的访问量:访问量飙升
- 超出预期的数据量:系统中是否存在一次性提取大量数据到内存的代码
- 内存泄漏
解决思路一般是:
一、堆dump文件获取 1、通过参数配置自动获取dump文件(推荐) 2、jmap -dump:format=b,file=filename.hprof pid 二、MAT工具分析 1、分析大对象、堆中存储信息、可能存在的内存泄漏地方,便于定位问题位置
JVM内存和GC梳理
JVM内存和内存管理
GC
更多推荐
所有评论(0)