jvm调优整理
一些关于JVM的文章
https://mp.weixin.qq.com/s/qT8PgLBLDADttT2xNM4RxQ
https://mp.weixin.qq.com/s/vTtMQXsBpSYIith8LF5K4g
https://mp.weixin.qq.com/s/U0oDSUTzbx90X8CqVsAUhQ
https://mp.weixin.qq.com/s/YYe4WfhG7ImjYC7tFEOemQ
https://mp.weixin.qq.com/s/rT_yr_hG7BnRRXIrD0l9tg
运行时数据区
程序计数器
JVM支持多线程同时执行,每个线程都有自己的PC Register,线程正在执行的方法叫当前方法,如果是java代码,PC Register里面存放的就是当前正在执行的指令地址,如果是C代码,则为空。
虚拟机栈
Java虚拟机栈是线程私有的,他的生命周期和线程相同,虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个站帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每个方法从调用直至完成的过程,就对应一个虚拟机栈中入栈到出栈的过程。
堆
Java堆是Java虚拟机所管理内存中最大的一块,堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆可以处于物理上不连续的内存空间中,只要是逻辑上连续的即可。
方法区
方法区和Java堆一样,是各个线程共享的内存区域,他用于存储已被虚拟机加载的类信息,常量,静态变量及时编译后的代码等数据,虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但他却有一个别名叫做Non-Heap(非堆),目的是与java堆区分开来。java8之前称之为PermSpace,Java8之后称之为MetaSpace。
Metaspace
Metaspace=Class,Package,Metho,Field,字节码,常量池,符号引用等等。
CCS : 32位指针的Class
CodeCache: JIT 编译后的本地代码,JNI使用的C代码
常量池
运行时常量池是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存储。
本地方法栈
与虚拟机栈发挥的作用是非常类似的,他们之间的区别不过是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。
常用的JVM参数
参数名称 | 说明 |
---|---|
-Xms;-Xmx | 最小\最大堆内存 |
-XX:NewSize; -XX:MaxNewSize | 新生代大小\新生代最大尺寸 |
-XX:NewRatio | new和Old区的比例 |
-XX:SuriviorRatio | Surivior和Eden区的比例 |
-XX:MetaspaceSize;-XX:MaxMetaspaceSize | Metaspace的大小和最大尺寸 |
-XX:+UseCompressedClassPointers | 是否启用压缩类指针 |
-XX:CompressedClassSpaceSize | 压缩类空间的大小 |
-XX:InitialCodeCacheSize;-XX:ReservedCodeCacheSize | codeCache的初始大小和最大大小 |
-XX:PertenureSizeThreshold | 超过该大小的对象直接进入老年代 |
-XX:MaxTenuringThreshold | 对象年龄到达该阈值后晋升到老年代 |
-XX:+PrintTenuringDistribution | 发生YoungGC的时候打印存活对象的年龄情况 |
-XX:TragetSurivorRatio | Surivior区存活对象的比例的平均年龄和MaxTenuringThreshold取最小值作为对象晋升老年代标准 |
java的垃圾回收算法
常用的垃圾收集器
类别 | 名称 | 参数 |
---|---|---|
串行垃圾收集器 | Serial,SerialOld | -XX:+UseSerialGC -XX:UserSerialOldGC |
并行收集器 | Parallel Scavenge,ParallelOld | -XX:+UseParallelGC -XX:+UseParallelOldGC |
并发垃圾收集器 | CMS,G1 | -XX:+UseConcMarkSweepGC -XX:UseParNewGC;-XX:+UseG1GC |
并行vs并发
并行:(吞吐量优先)指多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态,适合科学计算,后台处理等弱交互场景。
并发:(响应时间优先)指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候不会停顿用户程序的运行。适合对响应时间有要求的场景,比如:Web
停顿时间vs吞吐量
停顿时间:垃圾收集器做垃圾回收中断应用执行的时间,-XX:MaxGCPauseMillis
吞吐量:花在垃圾收集的时间和花在应用时间的占比。-XX:GCTimeRatio=<n>
,垃圾收集时间占1/(1+n)
理想情况就是停顿时间最小,但是吞吐量最大
如何选择垃圾收集器
- 优先调整堆的大小让服务器自己来选择
- 如果内存小于100M,使用串行收集器
3.如果是单核,并且没有停顿时间的要求,串行或者JVM自己去选择 - 如果停顿时间超过1秒,选择并行或者JVM自己来选
- 如果允许停顿时间超过1秒。选择并行或者JVM自己来选
- 如果响应时间最重要,并且不能超过1秒,使用并发收集器
Parallel Collector
并行垃圾收集:当应用程序中垃圾过多时,并行垃圾收集器会暂停用户线程并开启多个垃圾收集线程进行垃圾回收,当垃圾回收完毕后,继续执行用户程序。
可以通过使用-XX:+UseParallelGC
手动开启,(Server模式默认开启)
通过使用-XX:ParallelGCThreads
=<N>开启多少个GC线程。
如果CPU核数大于8核,会默认开启5:8个线程。
如果CPU核数小于8核,会more开启跟CPU核数相同的线程数
自适应特性
根据设定的参数去自动设置垃圾回收线程数
参数 | 说明 |
---|---|
-XX:MaxGCPauseMillis | 最大停顿时间 |
-XX:GCTimeRatio | 吞吐量 |
-Xmx | 最大堆大小 |
动态内存调整
自适应特性会动态的调整堆各个分区的大小来满足自适应的条件
参数 | 说明 |
---|---|
-XX:YoungGenerationSizeIncrement | 调整Young区内存大小,默认值是20% |
-XX:TenuredGenerationSizeIncrement | 调整Old区内存大小,默认值20% |
-XX:AdaptiveSizeDecrementScaleFactor | 减小堆内存大小,默认值4% |
生产环境很少使用自适应的方式调整,一般使用手动的形式调整堆内存大小
CMS Collector
- 并发收集
- 低停顿 低延迟
- 老年代垃圾收集器
收集过程
- CMS initial mark: 初始标记Root,STW
- CMS concurrent mark: 并发标记
- CMS-concurrent-preclean:并发预清理
- CMS remark: 重新标记,STW
- CMS concurrent sweep: 并发清楚
- CMS-concurrent-reset: 并发重置
缺点
- CPU敏感:垃圾回收时会占用一些线程,占用一定的计算机资源
- 浮动垃圾:执行垃圾回收时,由于应用程序仍然在工作,所以会产生一些浮动垃圾
- 空间碎片:采用标记清楚算法,垃圾回收后会产生一定的内存碎片
调优参数
参数 | 说明 |
---|---|
-XX:ConcGCThreads | 并发的GC线程数 |
-XX:+UseCMSCompactAtFullCollection | FullGC之后做压缩 |
-XX:CMSFullGCsBeforeCompaction | 多少次FullGC之后压缩一次 |
-XX:CMSInitiatingOccupancyFraction | Old区占用多少存活对象的时候进行FullGC |
-XX:+UseCMSInitiatingOccupancyOnly | 是否动态可调 |
-XX:+CMSScavengeBeforeRemark | FullGC之前先做YGC |
-XX:+CMSClassUnloadingEnabled | (JDK7之前)启用回收Perm区 |
G1垃圾收集器
-
Region
新生代和老年代已不是物理隔离,只是逻辑上的一个概念,将内存分为很多Region。
一部分Region为Young区,一部分Region为Old区。H区是G1的特点,用于存放大对象,当对象的大小超过Region的一半,会被存储到H区,图中蓝色的region代表新生代,红色的region代表正在进行垃圾回收的区域。
图片源于oracle官网,侵;删 -
SATB
Snapshot-At-The-Beginning,他是通过Root Tracing得到的,GC开始的时候存活对象的快照。 -
RSet:
记录了其他Region中的对象引用本Region中的对象的关系,属于points-into结构,(谁引用了我的对象)
常用参数
参数 | 说明 |
---|---|
-XX:InitiatingHeapOccupancyPercent | 堆占有率达到这个数值则触发global concurrent marking,默认45% |
-XX:G1HeapWastePercent | 在global concurrent marking结束之后,可以知道区有多少空间被回收,在每次YGC之后和再次发生MixedGC之前,会检查垃圾占比是否达到次参数,只有达到了,下次才会发生MixedGC。 |
-XX:G1MixedGCLiveThresholdPercent | Old区的Region被回收的时候存活对象占比 |
-XX:G1MixedGCCountTarget | 一次global concurrent marking之后,最多执行MixedGC 次数 |
-XX:G1OldCSetRegionThresholdPercent | 一次MixedGC中能被CSet的最多old区的Region数量 |
-XX:+UseG1GC | 开启G1 |
-XX:G1HeapRegionSize | Region的大小,1-32M,最多不能超过2048个 |
-XX:MaxGCPauseMillis | 最大停顿时间 |
-XX:G1NewSizePercent,-XX:G1MaxNewSizePercent | Young区占比和Young区最大占比 |
-XX:G1ReserverPercent | 发生YoungGC时保留堆内存的百分比,防止To区不够导致内存溢出 |
-XX:ParallelGCThreads | 并行GC线程数/STW线程数 |
-XX:ConcGCThreads | 并发线程数=1/4*并行 |
最佳实践
- 年轻代大小:避免使用-Xmn,-XX:NewRatio等显示设置Young区的大小,会暂停时间目标。
- 暂停时间目标:暂停时间不要太苛刻,其吞吐量目标是90%的应用程序和10%的垃圾回收时间,太苛刻会直接影响到吞吐量。
是否需要切花到G1?
- 50%以上的堆被存活对象占用
- 对象分配和晋升的速度非常大
- 垃圾回收时间特别长,超过了1秒
具备以上特性的一个或多个,可以切换成G1
可视化日志分析工具
打印日志相关参数
参数 | 说明 |
---|---|
-XX:PrintGCDetails | 打印GC详细信息 |
-XX:PrintGCTimeStamps | 打印GC时间戳 |
-XX:PrintGCDateStamps | 打印GC日期时间戳 |
Xloggc:$PATH/log/gc.log | 设置GC日志存放路径 |
-XX:+PrintHeapAtGC | 当发生GC时打印堆信息 |
-XX:+PrintTenuringDistribution | 发生GC时打印Young区年龄信息 |
日志格式
- ParallelGC
JVM_OPS="
-XX:+UseParallelGC
-XX:PrintGCDetails
-XX:PrintGCTimeStamps
-XX:PrintGCDateStamps
Xloggc:/root/log/gc.log
"
PROJECT_PATH="/root/customer-spring-boot-0.0.1-SNAPSHOT.jar"
nohup java -jar $JVM_OPS $PROJECT_PATH &
GC 日志格式
Java HotSpot(TM) 64-Bit Server VM (25.191-b12) for linux-amd64 JRE (1.8.0_191-b12), built on Oct 6 2018 05:43:09 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 995732k(212876k free), swap 2097148k(2096884k free)
CommandLine flags: -XX:InitialHeapSize=15931712 -XX:MaxHeapSize=254907392 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
2020-03-08T08:49:50.406+0800: 0.204: [GC (Allocation Failure) [PSYoungGen: 4096K->512K(4608K)] 4096K->1195K(15872K), 0.0030710 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-03-08T08:49:50.505+0800: 0.303: [GC (Allocation Failure) [PSYoungGen: 4608K->480K(8704K)] 5291K->1457K(19968K), 0.0013605 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T08:49:50.666+0800: 0.464: [GC (Allocation Failure) [PSYoungGen: 8672K->480K(8704K)] 9649K->1876K(19968K), 0.0014945 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T08:49:50.728+0800: 0.526: [GC (Allocation Failure) [PSYoungGen: 8672K->480K(16896K)] 10068K->2092K(28160K), 0.0014879 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T08:49:50.873+0800: 0.671: [GC (Allocation Failure) [PSYoungGen: 16864K->498K(16896K)] 18476K->2459K(28160K), 0.0018209 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2020-03-08T08:49:51.001+0800: 0.799: [GC (Allocation Failure) [PSYoungGen: 16882K->832K(34304K)] 18843K->2792K(45568K), 0.0020752 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T08:49:51.366+0800: 1.164: [GC (Allocation Failure) [PSYoungGen: 33600K->1298K(34304K)] 35560K->3562K(45568K), 0.0053209 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T08:49:51.650+0800: 1.448: [GC (Allocation Failure) [PSYoungGen: 34066K->1504K(66560K)] 36330K->4065K(77824K), 0.0034061 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-03-08T08:49:52.437+0800: 2.235: [GC (Allocation Failure) [PSYoungGen: 66528K->2032K(67072K)] 69089K->5733K(78336K), 0.0057108 secs] [Times: user=0.00 sys=0.01, real=0.00 secs]
2020-03-08T08:49:52.974+0800: 2.772: [GC (Metadata GC Threshold) [PSYoungGen: 45461K->2496K(79360K)] 49162K->6973K(90624K), 0.0828810 secs] [Times: user=0.02 sys=0.07, real=0.09 secs]
2020-03-08T08:49:53.057+0800: 2.855: [Full GC (Metadata GC Threshold) [PSYoungGen: 2496K->0K(79360K)] [ParOldGen: 4477K->6252K(14336K)] 6973K->6252K(93696K), [Metaspace: 20221K->20221K(1069056K)], 0.1567279 secs] [Times: user=0.05 sys=0.08, real=0.15 secs]
2020-03-08T08:49:54.890+0800: 4.688: [GC (Allocation Failure) [PSYoungGen: 76800K->2356K(79872K)] 83052K->8608K(94208K), 0.0480843 secs] [Times: user=0.01 sys=0.03, real=0.05 secs]
2020-03-08T08:49:55.770+0800: 5.568: [GC (Allocation Failure) [PSYoungGen: 79156K->3040K(77824K)] 85408K->10505K(92160K), 0.0305249 secs] [Times: user=0.00 sys=0.02, real=0.03 secs]
- 先打印java虚拟机版本,内存信息。
Java HotSpot(TM) 64-Bit Server VM (25.191-b12) for linux-amd64 JRE (1.8.0_191-b12), built on Oct 6 2018 05:43:09 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 995732k(212876k free), swap 2097148k(2096884k free)
- 打印虚拟机的参数
CommandLine flags: -XX:InitialHeapSize=15931712 -XX:MaxHeapSize=254907392 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
- 具体格式
2020-03-08T08:49:50.406+0800: 0.204: [GC (Allocation Failure) [PSYoungGen: 4096K->512K(4608K)] 4096K->1195K(15872K), 0.0030710 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
时间戳:[GC(发生GC原因)[Young区GC:垃圾回收前Young区大小->回收后Young(Young区总大小),GC时间][Times: ]
CMS垃圾收集器
JVM_OPS="
-XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-Xloggc:/root/log/gc.log
Xloggc:/root/log/gc.log
"
日志格式
Java HotSpot(TM) 64-Bit Server VM (25.191-b12) for linux-amd64 JRE (1.8.0_191-b12), built on Oct 6 2018 05:43:09 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 995732k(264360k free), swap 2097148k(2096628k free)
CommandLine flags: -XX:InitialHeapSize=15931712 -XX:MaxHeapSize=254907392 -XX:MaxNewSize=84586496 -XX:MaxTenuringThreshold=6 -XX:OldPLABSize=16 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
2020-03-08T09:13:38.799+0800: 0.213: [GC (Allocation Failure) 2020-03-08T09:13:38.800+0800: 0.214: [ParNew: 4371K->510K(4928K), 0.0043066 secs] 4371K->1213K(15872K), 0.0055786 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-03-08T09:13:38.898+0800: 0.312: [GC (Allocation Failure) 2020-03-08T09:13:38.898+0800: 0.312: [ParNew: 4926K->511K(4928K), 0.0020593 secs] 5629K->1724K(15872K), 0.0020975 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:38.963+0800: 0.377: [GC (Allocation Failure) 2020-03-08T09:13:38.963+0800: 0.377: [ParNew: 4927K->413K(4928K), 0.0007817 secs] 6140K->1625K(15872K), 0.0008149 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:39.050+0800: 0.464: [GC (Allocation Failure) 2020-03-08T09:13:39.051+0800: 0.464: [ParNew: 4829K->512K(4928K), 0.0015297 secs] 6041K->1957K(15872K), 0.0015739 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:39.080+0800: 0.493: [GC (Allocation Failure) 2020-03-08T09:13:39.080+0800: 0.493: [ParNew: 4928K->365K(4928K), 0.0015326 secs] 6373K->2176K(15872K), 0.0015661 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:39.117+0800: 0.531: [GC (Allocation Failure) 2020-03-08T09:13:39.117+0800: 0.531: [ParNew: 4781K->270K(4928K), 0.0008508 secs] 6592K->2081K(15872K), 0.0008847 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.710+0800: 2.124: [GC (Allocation Failure) 2020-03-08T09:13:40.710+0800: 2.124: [ParNew: 4708K->290K(4928K), 0.0018457 secs] 10036K->5739K(15872K), 0.0018818 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.741+0800: 2.155: [GC (Allocation Failure) 2020-03-08T09:13:40.741+0800: 2.155: [ParNew: 4706K->271K(4928K), 0.0016969 secs] 10155K->5871K(15872K), 0.0017322 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.769+0800: 2.183: [GC (CMS Initial Mark) [1 CMS-initial-mark: 5599K(10944K)] 7333K(15872K), 0.0026634 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.771+0800: 2.185: [CMS-concurrent-mark-start]
2020-03-08T09:13:40.778+0800: 2.192: [CMS-concurrent-mark: 0.007/0.007 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2020-03-08T09:13:40.778+0800: 2.192: [CMS-concurrent-preclean-start]
2020-03-08T09:13:40.779+0800: 2.193: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.798+0800: 2.212: [GC (CMS Final Remark) [YG occupancy: 3264 K (4928 K)]2020-03-08T09:13:40.799+0800: 2.213: [Rescan (parallel) , 0.0021936 secs]2020-03-08T09:13:40.801+0800: 2.215: [weak refs processing, 0.0000422 secs]2020-03-08T09:13:40.801+0800: 2.215: [class unloading, 0.0020634 secs]2020-03-08T09:13:40.803+0800: 2.217: [scrub symbol table, 0.0011121 secs]2020-03-08T09:13:40.805+0800: 2.218: [scrub string table, 0.0002549 secs][1 CMS-remark: 5599K(10944K)] 8864K(15872K), 0.0067148 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2020-03-08T09:13:40.834+0800: 2.248: [CMS-concurrent-sweep-start]
2020-03-08T09:13:40.836+0800: 2.250: [CMS-concurrent-sweep: 0.002/0.002 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2020-03-08T09:13:40.836+0800: 2.250: [CMS-concurrent-reset-start]
2020-03-08T09:13:40.837+0800: 2.251: [CMS-concurrent-reset: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.839+0800: 2.253: [GC (Allocation Failure) 2020-03-08T09:13:40.839+0800: 2.253: [ParNew: 4687K->509K(4928K), 0.0019851 secs] 9540K->5362K(15872K), 0.0020204 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2020-03-08T09:13:40.866+0800: 2.280: [GC (Allocation Failure) 2020-03-08T09:13:40.866+0800: 2.280: [ParNew: 4925K->403K(4928K), 0.0023671 secs] 9778K->5494K(15872K), 0.0024049 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
G1垃圾收集器
JVM_OPS="
-XX:+UseG1GC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-Xloggc:/root/log/gc.log
Xloggc:/root/log/gc.log
"
日志格式
Java HotSpot(TM) 64-Bit Server VM (25.191-b12) for linux-amd64 JRE (1.8.0_191-b12), built on Oct 6 2018 05:43:09 by "java_re" with gcc 7.3.0
Memory: 4k page, physical 995732k(264260k free), swap 2097148k(2096628k free)
CommandLine flags: -XX:InitialHeapSize=15931712 -XX:MaxHeapSize=254907392 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
2020-03-08T09:23:48.403+0800: 2.194: [GC pause (G1 Evacuation Pause) (young), 0.0033536 secs]
[Parallel Time: 3.3 ms, GC Workers: 1]
[GC Worker Start (ms): 2194.2]
[Ext Root Scanning (ms): 0.9]
[Update RS (ms): 1.2]
[Processed Buffers: 9]
[Scan RS (ms): 0.0]
[Code Root Scanning (ms): 0.0]
[Object Copy (ms): 1.1]
[Termination (ms): 0.0]
[Termination Attempts: 1]
[GC Worker Other (ms): 0.0]
[GC Worker Total (ms): 3.2]
[GC Worker End (ms): 2197.4]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.0 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 5120.0K(5120.0K)->0.0B(4096.0K) Survivors: 1024.0K->1024.0K Heap: 12.8M(16.0M)->8294.0K(16.0M)]
[Times: user=0.01 sys=0.00, real=0.01 secs]
2020-03-08T09:23:48.434+0800: 2.225: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0035230 secs]
[Parallel Time: 3.4 ms, GC Workers: 1]
[GC Worker Start (ms): 2224.7]
[Ext Root Scanning (ms): 1.2]
[Update RS (ms): 1.1]
[Processed Buffers: 8]
[Scan RS (ms): 0.0]
[Code Root Scanning (ms): 0.0]
[Object Copy (ms): 1.0]
[Termination (ms): 0.0]
[Termination Attempts: 1]
[GC Worker Other (ms): 0.0]
[GC Worker Total (ms): 3.4]
[GC Worker End (ms): 2228.1]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.0 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 4096.0K(4096.0K)->0.0B(4096.0K) Survivors: 1024.0K->1024.0K Heap: 12.1M(16.0M)->8199.0K(16.0M)]
[Times: user=0.01 sys=0.00, real=0.01 secs]
2020-03-08T09:23:48.437+0800: 2.228: [GC concurrent-root-region-scan-start]
2020-03-08T09:23:48.471+0800: 2.262: [GC concurrent-root-region-scan-end, 0.0338796 secs]
2020-03-08T09:23:48.471+0800: 2.262: [GC concurrent-mark-start]
2020-03-08T09:23:48.499+0800: 2.291: [GC concurrent-mark-end, 0.0282595 secs]
2020-03-08T09:23:48.500+0800: 2.291: [GC remark 2020-03-08T09:23:48.500+0800: 2.291: [Finalize Marking, 0.0000562 secs] 2020-03-08T09:23:48.500+0800: 2.291: [GC ref-proc, 0.0002198 secs] 2020-03-08T09:23:48.500+0800: 2.291: [Unloading, 0.0045842 secs], 0.0158981 secs]
[Times: user=0.01 sys=0.01, real=0.02 secs]
2020-03-08T09:23:48.516+0800: 2.307: [GC cleanup 11M->11M(16M), 0.0001329 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
1. 在线工具 http://gceasy.io
2. GCViewer
GC 调优实战
- 开启GC相关参数
参数 | 说明 |
---|---|
-XX:+PrintGCDetails | 打印GC详细信息 |
-XX:+PrintGCTimeStamps | 打印GC时间戳 |
-XX:+PrintGCDateStamps | 打印GC日期时间戳 |
Xloggc:$PATH/log/gc.log | 设置GC日志存放路径 |
-XX:+PrintHeapAtGC | 当发生GC时打印堆信息 |
-XX:+PrintTenuringDistribution | 发生GC时打印Young区年龄信息 |
-XX:+DisabeExplicitGC | 禁用System.gc方法 |
-XX:+HeapDumpOnOutOfMemoryError | 发生堆内存溢出时dump一下heap快照 |
-XX:HeapDumpPath | 堆内存快照的存放路径 |
ParallelGC 调优原则
- 除非非常确定,否则不要设置最大堆内存
- 优先设置吞吐量目标
- 如果吞吐量不达标,调大最大内存,但是不能让操作系统使用swap内存。如果仍然达标不到,降低吞吐量目标
- 吞吐量能达到,GC时间太长,设置停顿时间的目标。
下面是我的SpringBoot项目启动时的GC日志分析结果
-
发生了15次gc,一次fullGC,14次YoungGC,YoungGC中有13次的原因是因为对象分配内存不足导致,一次是因为Metaspace内存不足导致。FullGC是因为Metaspace内存不足导致。垃圾收集器的吞吐量是97.46%,平均响应时间0.1秒
我们将Metaspace的大小调高试一下
-XX:MetaspaceSize=40M
发生了14次GC,没有发生FullGC
垃圾收集器的吞吐量是98.73,平均响应时间0.05秒
G1垃圾收集器调优
- 年轻代大小:避免使用-Xmn,-XX:NewRatio等显式设置Young区大小,会覆盖暂停时间目标。
- 暂停时间目标:暂停时间不要太严苛,其吞吐量是90%的应用程序时间和10%的垃圾回收时间,太严苛会直接影响到吞吐量。
- 调优MixedGC调优:
参数 |
---|
-XX:InitiatingHeapOccupancyPercent |
-XX:G1MixedGCLiveThresholdPercent |
-XX:G1HeapWastePercent |
-XX:G1MixedGCCountTarget |
-XX:G1OldCsetRegionThresholdPercent |