JVM全文
参数选项类型
- 标准参数选项
- 比较稳定,以
-开头java -help查看server模式,大内存的应用程序,默认使用并行垃圾收集器;client模式,内存较小的桌面应用程序,只能使用serial串行垃圾回收器
- -X参数选项
- 非标准化,功能稳定,
-X开头java -X查看-Xint禁用JIT,只用解释器;-Xcomp所有字节码被编译成本地代码再执行;-Xmixed混合模式、默认模式,内部选择-Xms<size>=-XX:InitialHeapSize初始堆大小;-Xmx<size>=-XX:MaxHeapSize堆最大大小;-Xss<size>=-XX:ThreadStackSize线程栈大小
- -XX参数选项
- 实验性的,用于开发和调试JVM
- Boolean类型,
+/-区分- 非Boolean类型,
-XX:<option>=<value>-XX:+PrintFlagsFinal输出所有参数的名称和默认值,默认不包括Diagnostic/Experimental诊断/实验性参数,配合-XX:+UnlockDiagnosticVMOptions/-XX:+UnlockExperimentalVMOptions使用
添加JVM参数
- Idea
- jar
java -XX:+PrintFlagsFinal -jar demo.jar
- jinfo 运行时修改,看调优命令行工具
常用JVM参数选项
打印设置的XX选项
-XX:+PrintCommandLineFlags程序运行前打印出用户手动设置或JVM自动设置的XX选项-XX:+PrintFlagInitial打印出所有XX选项的默认值-XX:+PrintFlagsFinal打印出XX选项在运行程序时生效的值-XX:+PrintVMOptions打印JVM参数
堆栈方法区内存大小设置
Xss128k每个线程的栈大小,等价于-XX:ThreadStackSize=128k
堆
-Xms<size>=-XX:InitialHeapSize初始堆大小,初始比最大小,报错-Xmx<size>=-XX:MaxHeapSize堆最大大小-Xss<size>=-XX:ThreadStackSize线程栈大小-Xmn<size>同时设置年轻代初始大小和最大大小,推荐设置为整个堆的3/8,等价于-XX:NewSize=<size>-XX:MaxNewSize=<size>-XX:SurvivorRatio=8设置Eden和一个Survivor比例,显示定义了,以定义的为准-XX:+UseAdaptiveSizePolicy自适应内存分配的策略,默认实际上为6:1:1
- CMS垃圾回收器默认关闭,新生代比例默认就是8:1:1,实际上也是
- G1垃圾回收器默认是开启的,内存空间是灵活分配的
![]()
-XX:NewRatio=4设置老年代和新生代的比例-XX:PretenureSizeThreadshold设置大于此阈值的对象直接分配在老年代,单位字节;只对Serial、ParNew收集器有效-XX:MaxTenuringThreshold=15默认值为15,每次MinorGC后,对象年龄+1,大于设置的这个阈值后,进入老年代-XX:PrintTenuringDistribution每次MinorGC后,都打印当前使用的Survivor中对象的年龄分布-XX:TargetSurvivorRatio每次MinorGC后,Survivor区域期望的占比
方法区
- 永久代
-XX:PermSize=256m设置初始值-XX:MaxPermSize=256m最大值
- 元空间
-XX:MetaspaceSize初始大小-XX:MaxMetaspaceSize最大值-XX:+UseCompressedOops压缩对象指针-XX:+UseCompressedClassPointers压缩类指针-XX:+CompressedClassSpaceSize设置存储类结构的数据(Klass)大小,默认1G
committed(Non-class Metaspace) + committed(Compressed Class Space) <= MaxMetaspaceSize
如果 MaxMetaspaceSize 设置为小于 CompressedClassSpaceSize,则后者会自动减小为
- 直接内存
-XX:MaxDirectMemorySize大小,默认与java堆一样
OutOfMemory相关
-XX:+HeapDumpOnoutOfMemoryError出现OOM时,输出dump文件-XX:+HeapDumpBeforeFullGC出现FullGC之前,输出dump文件-XX:HeapDumpPath=/Users/mzx/Desktop/java/jvm/test2.hprof输出dump文件的路径,文件名,如果存在,会自动改文件名-XX:OnOutOfMemoryError指定一个可执行程序或者脚本的路径,发生OOM时,执行脚本
垃圾回收器相关
- 垃圾回收器
- Serial回收器
-XX:+UseSerialGC,同时指定,单核CPU - ParNew回收器
-XX:+UseParNewGC指定垃圾收集器,jdk9及以后弃用-XX:ParallelGCThreads=2设置线程数量,默认开启和CPU数量相同
- Parallel回收器,JDK8默认
-XX:UseParallelGC,互相激活,默认,跟老年代是一组搭配-XX:UseParallelOldGC-XX:ParallelGCThreads设置年轻代线程数量,默认开启和CPU数量相同;CPU数量小于8,默认为CPU数量;CPU数量大于8,值为3+[5*count]/8-XX:MaxGCPauseMills,最大停顿时间,STW的时间,自动调整java堆的大小和分配;暂停时间越长->比例越大,影响下面的参数;暂时时间越短->越频繁->总时间越长->吞吐量下降(某个时间段)-XX:GCTimeRatio,垃圾回收时间占总时间的比例,=1 / (N + 1),默认值N=99;-XX:+UseAdaptiveSizePolicy,自适应调节,年轻代大小,Eden和s1/s0的比例,晋升老年代的阈值自动调整
- CMS回收器
-XX:+UseConcMarkSweepGC启用CMS,自动打开ParNew,采用ParNew+CMS+Serial Old-XX:CMSInitiatingOccupancyFraction=92,堆内存使用阈值,默认=-1,降低Full GC执行次数;如果内存增长很快,设置较小的值,给用户线程留出足够空间,避免频繁触发老年代串行收集器;内存增长很慢,设一个较大的值,降低CMS出发频率,减少老年代回收可以较明显地改善应用程序性能-XX:+UseCMSCompactAtFullCollection,执行完CMS后,进行压缩整理-XX:CMSFullGCsBeforeCompaction=0,执行多少次CMS Full GC后,进行压缩整理-XX:ParallelCMSThreads,设置CMS的线程数量,默认值为CPU个数,结果为(ParallelGCThreads+3)/4
- G1回收器
-XX:+UseG1GC,手动设置-XX:G1HeapRegionSize=16m设置每个Region的大小,值是2的幂,范围是1~32MB,目标根据最小的Java对大小,划分出2048个区域,堆空间的大小为2G~64G,默认是对内存的1/2000-XX:MaxGCPauseMillis,设置期望达到的最大GC停顿时间指标,不一定能达到,默认200ms-XX:ParallelGCThreads,设置STW时GC线程数的值,最多8-XX:ConcGCThreads,设置并发标记的线程数,将n设置为并行垃圾回收线程数 占ParallelGCThread的1/4左右-XX:InitiatingHeapOccupancyPercent,设置触发并发GC周期的Java堆占用率阈值,超过此值,触发GC,默认为45-XX:G1NewSizePercent-XX:G1MaxNewSizePercent新生代占整个堆内存的最小百分比(默认5%)、最大百分比(默认60%)-XX:G1ReservePercent=10保留内存区域,防止to区溢出
GC日志相关
-XX:+PrintGC,输出GC日志,类似-verbose:gc-XX:+PrintGCDetails,输出GC的详细日志,进程退出时输出当前内存各区域的分配情况-XX:+PrintGCTimeStamps,不能独立使用,输出GC的时间戳(以基准时间的形式,JVM启动以来到现在的时间)0.389-XX:+PrintGCDateStamps,不能独立使用,输出GC的时间戳(以日期的形式)2021-10-15T19:07:13.682+0800-XX:+PrintHeapAtGC,进行GC的前后打印出堆的信息-Xloggc:/Users/apple/Desktop/java/jvm/logs/gc.log日志文件的输出,配合上面的使用-XX:+PrintGCApplicationStoppedTime打印GC时线程停顿时间- 其他参数
其他
通过代码获取参数
- 堆内存
//虚拟机中堆初始内存总量 *64为系统内存大小
long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
//虚拟机中堆最大内存,java试图使用的最大堆内存 *4为系统内存大小
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
ManagementFactory
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage usage = memoryMXBean.getHeapMemoryUsage();
//Init Heap
System.out.println(usage.getInit() / 1024 / 1024);
//Max Heap
System.out.println(usage.getMax() / 1024 / 1024);
//Use Heap
System.out.println(usage.getUsed() / 1024 / 1024);
//Heap Memory Usage
System.out.println(memoryMXBean.getHeapMemoryUsage());
//Non-Heap Memory Usage
System.out.println(memoryMXBean.getNonHeapMemoryUsage());
//当前堆内存大小
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);
//空闲堆内存大小
System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);
//最大可用堆内存
System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);
GC日志
- SerialGC
- CMS
GC分类
- 部分收集,PartialGC,不是完整收集整个java堆
- 新生代收集,
MinorGC/YoungGC,只是新生代Eden/From/To的收集- 老年代收集,
MajorGC/OldGC, 只是老年代的收集;只有CMS会有单独收集老年代的行为;很多时候会和FullGC混淆使用;在进行老年代收集之前,通常会进行一次新生代收集- 混合收集,
MixedGC,收集整个新生代以及部分老年代的垃圾收集;只有G1有
- 整堆收集,FullGC,收集java堆和方法区的垃圾堆
- 老年代、方法区空间不足
- 显示调用System.gc()
- MinorGC进入老年代的平均大小大于老年代可用内存
- 大对象直接进去老年代,而老年代可用空间不足
GC日志结构
- GC开始到结束的时间
- user 进程执行用户态代码时间
- sys 进程在内核态消耗的cpu时间,在内核执行系统调用或等待系统事件所使用的时间
- real 程序从开始到结束的时钟时间
- real > user + sys IO负载非常重,CPU不够用
- YGC
2021-12-14T14:32:59.957+0800: //日志打印时间
12.565: //程序运行到现在经过的时间
[GC (Allocation Failure) //GC的原因,新生代没有足够的区域分配对象
[PSYoungGen: //使用的垃圾回收器 Parallel Scanvenge垃圾回收器
25600K->4084K(29696K)] //执行垃圾回收之前 -> 执行垃圾回收之后,括号中为新生代的总大小 9/10 减去一份to区
25600K->24443K(98304K), //java堆总大小的变化 新生代9/10 + 老年代,刚开始还没有使用老年代,所以25600k相等
0.0164968 secs] //整个GC花费的时间
[Times: user=0.02 sys=0.01, real=0.02 secs]
- FullGC
2021-12-14T14:33:28.055+0800:
40.663:
[Full GC (Ergonomics) //系统自适应导致的GC (System)调用System.gc()触发的gc
[PSYoungGen: 25600K->2494K(29696K)] //新生代
[ParOldGen: 46608K->68493K(68608K)] //老年代
72208K->70988K(98304K), //总大小
[Metaspace: 3777K->3777K(1056768K)], //元空间
0.0369101 secs]
[Times: user=0.07 sys=0.02, real=0.04 secs]
日志工具
java -jar gcviewer-1.36.jar
- GCEasy官网 更全面