调优-JVM层GC调优
6、JVM层GC调优
6.1 JVM的内存调优
>
6.1.1 程序计数器PC Register
JVM支持多线程同时执行,每一个线程都有自己的PC Register,
线程正在执行的方法叫做当前方法,如果是java代码,
PC Register里面存放的就是当前正在执行的指令的地址,
如果是C代码,则为空。
6.1.2 虚拟机JVM Stacks
Java虚拟机栈( Java Virtual Machine Stacks )是线程私有的,它的,生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧 ,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
6.1.3 堆Heap
Java堆( Java Heap )是Java虚拟机所管理的内存中最大的一块。堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。
6.1.4 方法区Method Area
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分但是它却有一个别名叫做Non-Heap (非堆) , 目的是与Java堆区分开来。
6.1.6 常量池Run-Time Constant Pool
运行时常量池( Runtime Constant Pool )是方法区的一部分。
Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池( Constant Pool Table ),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
6.1.6 常量池Run-Time Constant Pool
运行时常量池( Runtime Constant Pool )是方法区的一部分。
Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池( Constant Pool Table ),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
6.1.6 非堆区
Metaspace= Class.Package、Method、Field.字节码、常量池、符号引用等等
CCS:32位指针的Class
CodeCache:JT编译后的本地代码、JNI使用的C代码
6.2 垃圾回收算法
- 实现:枚举根节点,做可达性分析
- 根节点:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等等
6.2.1 标记清除
算法:算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象A在标记完成后统一回收所有。
缺点: 效率不高。标记和清除两个过程的效率都不高。产生碎片。碎片太多会导致提前GC。
6.2.2 复制
算法:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块 上面,然后再把已使用过的内存空间一次清理掉。
优缺点: 实现简单,运行高效,但是空间利用率低(50%)。
6.2.2 标记整理
算法:标记过程仍然与“标记清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
优缺点:没有了内存碎片,但是整理内存比较耗时。
6.2.2 分带垃圾回收
- Young区使用复制算法
- Old区使用标记清除或标记整理
6.3 对象分配
- 对象优先在Eden区分配
- 大对象直接进入老年代:-XX:PretenureSizeThreshold
- 长期存活对象进入老年:-XX:MaxTenuringThreshold -XX:+PrintTenuringDistribution -XX:TargetSurvivorRatio
6.4 垃圾收集器
串行收集器Serial : Serial、Serial Old
并行收集器Parallel : Parallel Scavenge、Parallel Old ,吞吐量
并发收集器Concurrent: CMS、G1 ,停顿时间
6.4.1 并行VS并发
并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适合科学计算、后台处理等弱交互场景。
并发(Concurrent): 指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候不会停顿用户程序的运行。适合对响应时间有要求的场景,比如Web。
6.4.2 停顿时间VS吞吐量
停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。-XX:MaxGCPauseMillis
吞吐量:花在垃圾收集的时间和花在应用时间的占比。-XX:GCTimeRatio=
,垃圾收集时间占: 1/1+n
6.4.3 串行收集器
- -XX:+UseSerialGC -XX:+UseSerialOldGC
6.4.4 并行收集器
- 吞吐量优先
- -XX:+UseParallelGC, -XX:+UseParallelOldGC
- Server模式下的默认收集器
6.4.5 并发收集器
- 相应时间优先
- CMS: XX:+UseConcMarkSweepGC -XX:UseParNewGC
- G1:-XX:+UseG1GC
6.4.6 如何选择垃圾收集器
- 优先调整堆的大小让服务器自己来选择
- 如果内存小于100M ,使用串行收集器
- 如果是单核,并且没有停顿时间的要求,串行或者JVM自己选
- 如果允许停顿时间超过1秒,选择并行或者JVM自己选
- 如果响应时间最重要,并且不能超过1秒,使用并发收集器
更多介绍 https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
6.5 垃圾收集器-Parallel Collector(并行)
- -XX:+UseSerialGC 手动开启,Server默认开启
- -XX:ParallelGCThreads=
多少个GC线程
CPU>8 N=5/8
CPU<8 N=CPU
6.5.1 Parallel Collector Ergonomics
- -XX:MaxGCPauseMillis=
- -XX:GCTimeRatio=
- -Xmx
6.5.2 动态内存调整
- -XX:YoungGenerationSizeIncrement=
- -XX:TenuredGenerationSizeIncrement=
- -XX:AdaptiveSizeDecrementScaleFactor=
6.5.3 CMS Collector
- 并发收集
- 低停顿 低延迟
- 老年代收集器
6.5.3.1 CMS垃圾收集过程
- CMS initial mark:初始化标记Root,STW
- CMS concurrent mark:并发标记
- CMS-concurrent-preclean : 并发预清理
- CMS remark:重新标记,STW
- CMS concurrent sweep : 并发清除
- CMS-concurrent-reset :并发重置
CMS的缺点:CPU敏感 浮动垃圾 空间碎片
CMS的相关参数:
- -XX:ConcGCThreads: 并发的GC线程数
- -XX:+UseCMSCompactAtFullCollection : FullGC之后做压缩家差
- -XX.CMSFullGCsBeforeCompaction :多少次FullGC之后压缩一次
- -XX:CMSInitiatingOccupancyFraction:触发FullGC
- -XX:+UseCMSInitiatingOccupancyOnly:是否动态调
- -XX:+CMSScavengeBeforeRemark : FullGC之前先做YGC
- -XX:+CMSClassUnloadingEnabled :启用回收Perm区
6.5.4 iCMS
- 使用于单核或者双核
6.5.5 G1 Collector
简介
The first focus of G1 is to provide a solution for users running applications that require large heaps with limited GC latency. This means heap sizes of around 6GB or larger, and stable and predictable pause time below 0.5 seconds.
新生代和老生代收集器
6.5.5.1 G1的几个概念
- Region
- SATB:Snapshot-At-The-Beginning,它是通过Root Tracing得到的,GC开始时存活对象的快照
- RSet:记录了其他Region中的对象引用本Region中对象的关系,属于points-into结构(谁引用了我的对象)
YoungGC
- 新对象进入Eden区
- 存活对象拷贝Survivor区
- 存活时间达到年龄阈值时,对象晋升到Old区
MixedGC
- 不是FullGC,回收所有的Young和部分Old
- global concurrent marking
1.Initial marking pharse:标记GC Root,STW
2.Root regin scanning phase: 标记存活Regin
3.Concurrent marking phase: 标记存活的对象
4.Remark phase:重新标记,STW
5.Cleanup phase:部分STW
MixedGC时机
- InitiatingHeapOccupancyPercent:
堆占有率达到这个数值则触发global concurrent marking,默认45%。
- G1HeapWastePercent:
在global concurrent marking结束之后,可以知道区有多少空间要被回收,在每次YGC之后和再次发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。
MixedGC相关参数
- G1MixedGCLiveThresholdPercent:
Old区的region被回收时候的存活对象占比
- G1MixedGCCountTarget:
一次globalconcurrent marking之后,最多执行Mixed GC的次数
- G1OldCSetRegionThresholdercent:
一次Mixed GC中能被选入CSet的最多old区的region数量
常用参数
- -XX:+UseG1GC 开启G1
- -XX:G1HeapRegionSize=n, region的大小, 1-32M , 2048个
- -XX:G1NewSizePercent、 -XX:G1 MaxNewSizePercent
- -XX:G1ReservePercent= 10保留防止to space溢出
- -XX:ParallelGCThreads=n SWT线程数
- -XX:ConcGCThreads=n 并发线程数= 1/4*并行
最佳实践
- 年轻代大小:避免使用-Xmn、-XX:NewRatio等显式设置Young区大小,会覆盖暂停时间目标。
- 暂停时间目标:暂停时间不要太严苛,其吞吐量目标是90%的应用程序时间和10%的垃圾回收时间,太严苛会直接影响到吞吐量。
- 关于MixGC调优:
-XX:InitiatingHeapOccupancyPercent
-XX:G1MixedGCLiveThresholadPercent、 -XX:G1HeapWastePercent
-XX:G1MixedGCCountTarget、-XX:G1OldcSetRegionThresholdPercent
6.6 可视化GC日志分析工具
打印日志相关参数
tomcat/bin/catalina.sh
#搜索 /JAVA_OPTS
#添加以下参数后重启tomcat
- -XX:+PrintGCDetails -XX:+PrintGCTimeStampsXX: -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribut
gc日志在tomcat/logs/文件夹下生成
6.7 GC调优步骤
- 打印GC日志
- 根据日志得到关键性能指标
- 分析GC原因,调优JVM参数
初始设置
- -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_HOME/logs/ -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.Iog
6.7.1 Parallel GC调优
Parallel GC调优的指导原则
- 除非确定,否则不要设置最大堆内存
- 优先设置吞吐量目标
- 如果吞吐量目标达不到,调大最大内存,不能让OS使用Swap ,如果仍然达不到,降低目标。
Parallel GC调优
设置Metaspace大小
-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
添加吞吐量和停顿时间参数
-XX:GCTimeRatio=99 -XX:MaxGCPauseMillis=100
-修改动态扩容増量
- -XX:YoungGenerationsizelncrement=30
6.7.2 G1 GC调优
G1 GC最佳实践
- 年轻代大小:避免使用-Xmn、-XX:NewRatio等显式设置Young区大小,会覆盖暂停时间目标。
- 暂停时间目标:暂停时间不要太严苛,其吞吐量目标是90%的应用程序时间和10%的垃圾回收时间,太严苛会直接影响到吞吐量。
关于MixGC调优
- -XX:InitiatingHeapOccupancyPercent
- -XX:G1MixedGCLiveThresholdPercent、-XX:G1HeapWastePercent
- -XX:G1MixedGCCountTarget、-XX:G1OldCSetRegionThresholdPercent