JVM垃圾回收器与调优参数
引言
JVM为了更有效率的对堆空间进行垃圾回收,把堆空间进行了分代,分为年轻代、老年代和永久代(在1.8版本以后,永久代已经被彻底移除了,被元空间取而代之)。
当一个对象出生时,会首先选择在eden区为对象分配空间,当eden区被占满分配不下时,会触发一次Minor GC,MinorGC运行时,会将垃圾回收后eden区存活的对象移至Survivor1区,当Survivor某个区有了对象后,下一次进行MinorGC时,垃圾回收后会将eden区和存放对象的Survivor区里的剩余存活对象复制到另外一块空白的Survivor区,这就是年轻代垃圾回收的触发条件和回收过程。
对于老年代而言,老年代里的对象存活率相对较高,如果依然采用年轻代里的复制算法,耗时会相对较长,所以对老年代采用的时标记——清除或整理算法。CMS老年代回收器用的是标记清除,容易产生碎片,而PS+PO用的是标记整理,耗时相对于CMS稍微较长。可以这么说,在G1没有出来之前,如果追求的是低延迟,则使用CMS垃圾回收器;若追求的是高吞吐量,则可以选择使用PS + PO垃圾回收器。
基本概念
吞吐量(Throughput)
吞吐量(TPS)是指系统在单位时间内处理请求的数量。对于无并发的应用系统而言,吞吐量与响应时间成严格的反比关系,实际上此时吞吐量就是响应时间的倒数。前面已经说过,对于单用户的系统,响应时间(或者系统响应时间和应用延迟时间)可以很好地度量系统的性能,但对于并发系统,通常需要用吞吐量作为性能指标。
响应时间(Response Time)
响应时间是指系统对请求作出响应的时间。直观上看,这个指标与人对软件性能的主观感受是非常一致的,因为它完整地记录了整个计算机系统处理请求的时间。由于一个系统通常会提供许多功能,而不同功能的处理逻辑也千差万别,因而不同功能的响应时间也不尽相同,甚至同一功能在不同输入数据的情况下响应时间也不相同。所以,在讨论一个系统的响应时间时,人们通常是指该系统所有功能的平均时间或者所有功能的最大响应时间。当然,往往也需要对每个或每组功能讨论其平均响应时间和最大响应时间。
QPS每秒查询率(Query Per Second)
每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。对应fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。
JVM性能监控
JVM调优参数
JVM调优参数
参数分类
1、标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容。例如:-verbose:class(输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断);-verbose:gc(输出每次GC的相关情况);-verbose:jni(输出native方法调用的相关情况,一般用于诊断jni调用错误信息)。
2、非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容。例如:-Xms512m;-Xmx512m;-Xmn200m;-Xss128k;-Xloggc:file(与-verbose:gc功能类似,只是将每次GC事件的相关情况记录到一个文件中,文件的位置最好在本地,以避免网络的潜在问题。若与verbose命令同时出现在命令行中,则以-Xloggc为准)。
3、非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用。例如:-XX:PermSize=64m;-XX:MaxPermSize=512m。
查看参数
#查看命令行带的参数以及少量默认参数
java -XX:+PrintCommandLineFlags -version
#查看最终使用的参数(以列的形式列出,自行grep)
java -XX:+PrintFlagsFinal -XX:+UseG1GC -version | grep GC
#运行时打印输出GCDetails
-XX:+PrintGCDetails
#验证虚拟机参数是否正确
-XX:+PrintVMOptions
内存管理参数
参数 | 功能 | 默认值 | 描述 |
---|---|---|---|
-Xms | 初始Heap值 | 物理内存的1/64但小于1G | Server端JVM最好将-Xms和-Xmx设为相同值,避免每次垃圾回收完成后JVM重新分配内存 |
-Xmx | 可用最大Heap值 | 物理内存的1/4但小于1G | 默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列。最佳设值应该视物理内存大小及计算机内其他内存开销而定。 |
-Xmn | 年轻代大小 | 整堆的1/3 | 整个堆大小=年轻代大小 + 年老代大小 + 持久代大小,Sun官方推荐配置为整个堆的3/8 |
-Xss | 线程的Stack大小 | 1024kb | JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。可以适当减少增加thread可使用数量 |
-XX:SurvivorRatio | eden区和1个survivor区的比值 | 8 | 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 |
-XX:NewRatio | 老年代(除去永久代)与年轻代所占堆的比值 2/3:1/3 | 2 | 年轻代与年老代所占比值为1:4 ,使用CMS收集器无效 |
-XX:PermSize | 永久代(perm gen)初始值 | 物理内存的1/64 | 设置永久代(perm gen)初始值 |
-XX:MaxPermSize | 设置持久代最大值 | 物理内存的1/4 | 设置永久代(perm gen)最大值 |
-XX:+UseFastAccessorMethods | 内联优化 | false | 指内联函数的优化,何为内联函数呢,即一个方法里面调用了另外一个方法,JVM在编译的时候把被调用的方法合入到调用的方法里面,这样就能减少栈帧的创建(因为每一个方法执行时都会创建一个栈帧),节约内存 |
-XX:+DisableExplicitGC | 关闭System.gc()显示调用 | false | |
-XX:MaxTenuringThreshold | 垃圾最大年龄 | CMS:6 G1:15 Object有个标记位 | 对象存活的年龄,到达某个值后,就会晋升到老年代,而这个值最大为就是这个参数,年龄多大晋升到老年代,是GC器动态调节的,但是最大不会超过这个设定值 |
-XX:UseTlab | 使用线程本地分配缓存区 | true | TLAB只是让每个线程有私有的分配指针,但底下存对象的内存空间还是给所有线程访问的,只是其它线程无法在这个区域分配而已。 |
-XX:+TLABSize | tlab的初始大小, 默认0 | 0 | |
-XX:TLABWasteTargetPercent | TLAB占eden区的百分比 | 1% | |
-XX:TLABRefillWasteFraction | 设置进入TLAB空间,单个对象大小 | 64 | 如果,对象小于整个空间的1/64,则放在TLAB区;如果,对象大于整个空间的1/64,则放在堆区 |
-XX:+CollectGen0First | FullGC时是否先YGC | false | FullGC时是否先YGC |
-XX:+ScavengeBeforeFullGC | Full GC 前执行一次 Minor GC | true | 在执行 Full GC 前执行一次 Minor GC可以较少老年代中对象“意外”存活的现象。 |
垃圾回收器参数
并行收集器相关参数
参数 | 功能 | 默认值 | 描述 |
---|---|---|---|
-XX:+UseParallelGC | Full GC采用parallel MSC | 选择垃圾收集器为并行收集器.此配置仅对年轻代有效.即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集.(此项待验证) | |
XX:+UseParNewGC | 设置年轻代为并行收集 | 可与CMS收集同时使用JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值 | |
XX:+UseParallelOldGC | 年老代垃圾收集方式为并行收集(Parallel Compacting) | 这个是JAVA 6出现的参数选项 | |
-XX:ParallelGCThreads | 并行收集器的线程数 | 此值最好配置与处理器数目相等 同样适用于CMS | |
-XX:MaxGCPauseMillis | 每次年轻代垃圾回收的最长时间(最大暂停时间) | 如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值. | |
-XX:+UseAdaptiveSizePolicy | 自动选择年轻代区大小和相应的Survivor区比例 | 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开. | |
-XX:+ScavengeBeforeFullGC | Full GC前调用YGC | true | Do young generation GC prior to a full GC. (Introduced in 1.4.1.) |
CMS相关参数
参数 | 功能 | 默认值 | 描述 |
---|---|---|---|
-XX:+UseConcMarkSweepGC | 使用CMS内存收集 | 测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置. | |
-XX:ParallelCMSThreads | 设置CMS线程数量 | CPU核数一半 | 设置CMS线程数量,一般为CPU核数的一半,CMS线程是在老年代,要留一些CPU给用户线程 |
-XX:+AggressiveHeap | 优化大内存 | true | |
-XX+UseCMSCompactAtFullCollection | 在FULL GC的时候, 对年老代的压缩 | true | CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。可能会影响性能,但是可以消除碎片 |
-XX:CMSFullGCsBeforeCompaction | 多少次后进行内存压缩 | 0 | 由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理. |
-XX:+UseCMSInitiatingOccupancyOnly | 使用手动定义初始化定义开始CMS收集 | 禁止hostspot自行触发CMS GC | |
-XX:CMSInitiatingOccupancyFraction=70 | 使用cms作为垃圾回收使用70%后开始CMS收集 | 92 | |
-XX:CMSInitiatingPermOccupancyFraction | 设置Perm Gen使用到达多少比率时触发 | 92 | 设置Perm Gen使用到达多少比率时触发 |
-XX:+CMSClassUnloadingEnabled | 是否对永久代进行垃圾回收,类型卸载 | true | 是否对永久代进行垃圾回收,类型卸载 |
-XX:+CMSParallelRemarkEnabled | 开启并行标记 | true | 使用 CMS 作为GC方式,且开启并行标记,以减少服务端延迟时间 |
-XX:+CMSScavengeBeforeRemark | CMS Remark阶段前,执行一次 Minor GC | false | 在执行CMS Remark阶段前,执行一次 Minor GC,以降低STW的时间。通过 Minor GC 可以减少新生代对老年代对象的引用,这样可以减少根对象(GC Roots)数量,从而降低 CMS Remark 的工作量 |
PromotionFailed
垃圾回收时promotionfailed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。
解决方案一:
第一个原因最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。
解决方案一的改进方案:
又有改进了,上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS执行会比较频繁。改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有promotion failed。具体操作上,32位Linux和64位Linux好像不一样,64位系统似乎只要配置MaxTenuringThreshold参数,CMS还是有暂停。为了解决暂停问题和promotion failed问题,最后设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以CMS执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。
-Xmx4000M -Xms4000M -Xmn600M-XX:PermSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC-XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC-XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0-XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M-XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0-XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps-XX:+PrintHeapAtGC -Xloggc:log/gc.log
G1常用参数
参数 | 功能 | 默认值 | 描述 |
---|---|---|---|
-XX:+UseG1GC | 开启G1垃圾回收 | ||
-XX:MaxGCPauseMillis | 暂停时间 | 200ms | G1会尝试调整Young区的块数来达到这个值 |
-XX:+G1HeapRegionSize | 分区大小 | 建议逐渐增大该值,1 2 4 8 16 32。 随着size增加,垃圾的存活时间更长,GC间隔更长,配置了XX:G1HeapRegionSize,那么以配置为准,默认情况下,region_size = 平均堆大小((最大堆+最小堆)/2)除以2048个分区,最终取值1 2 4 8 16 32 最接近的一个,MIN_REGION_SIZE<=HeapRegionSize<=MAX_REGION_SIZE | |
-XX:G1NewSizePercent | 新生代比例下限 | 5% | |
-XX:G1MaxNewSizePercent | 新生代比例上限 | 60% | |
-XX:ConcGCThreads | 并发GC线程数 | 默认是-XX:ParallelGCThreads/4 | 在非STW期间的GC工作线程数,当然其他的线程很多工作在应用上。当并发周期时间过长时,可以尝试调大GC工作线程数,但是这也意味着此期间应用所占的线程数减少,会对吞吐量有一定影响。ConcGCThreads = (3 + ParallelGCThreads) / 4 |
-XX:ParallelGCThreads | STW阶段工作的GC线程数 | ||
-XX:InitiatingHeapOccupancyPercent | 触发全局并发标记的老年代使用占比 | 45% | |
-XX:G1HeapWastePercent | 触发Mixed GC的堆垃圾占比 | 默认值5% | 在全局标记结束后能够统计出所有Cset内可被回收的垃圾占整对的比例值,如果超过5%,那么就会触发之后的多轮Mixed GC |
-XX:G1ReservePercent | G1为分配担保预留的空间比例 | 默认10% | 老年代会预留10%的空间来给新生代的对象晋升,如果经常发生新生代晋升失败而导致Full GC,那么可以适当调高此阈值。但是调高此值同时也意味着降低了老年代的实际可用空间。 |
G1调优建议 |
- 不要手动设置新生代和老年代的大小,只设置这个堆的大小
- 不断调优暂停时间目标-XX:MaxGCPauseMillis
- 适当增加堆内存大小
G1GC
G1 GC是启发式算法,会动态调整年轻代的空间大小。目标也就是为了达到接近预期的暂停时间。G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)的。
- Young GC
Young GC主要是对Eden区进行GC,它在Eden空间耗尽时会被触发。在这种情况下,Eden空间的数据移动到Survivor空间中,如果Survivor空间不够,Eden空间的部分数据会直接晋升到老年代空间。Survivor区的数据移动到新的Survivor区中,也有部分数据晋升到老年代空间中。最终Eden空间的数据为空,GC停止工作,应用线程继续执行。 - Mixed GC
Mix GC不仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的老年代分区。GC步骤分2步: 全局并发标记(global concurrent marking)和 拷贝存活对象(evacuation)。
在进行Mix GC之前,会先进行global concurrent marking(全局并发标记)。 global concurrent marking的执行过程是怎样的呢?在G1 GC中,它主要是为Mixed GC提供标记服务的,并不是一次GC过程的一个必须环节。
Mixed GC的触发也是由一些参数控制。比如XX:InitiatingHeapOccupancyPercent表示老年代占整个堆大小的百分比,默认值是45%,达到该阈值就会触发一次Mixed GC。
G1的垃圾回收过程是和应用程序并发执行的,当Mixed GC的速度赶不上应用程序申请内存的速度的时候,Mixed G1就会降级到Full GC,使用的是Serial GC。Full GC会导致长时间的STW,应该要尽量避免。
JVM垃圾回收器与调优参数的更多相关文章
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
- JAVA高级篇(四、JVM垃圾回收和调优)
本文转自https://zhuanlan.zhihu.com/p/25539690 JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会 ...
- JVM调优参数、方法、工具以及案例总结
这种文章挺难写的,一是JVM参数巨多,二是内容枯燥乏味,但是想理解JVM调优又是没法避开的环节,本文主要用来总结梳理便于以后翻阅,主要围绕四个大的方面展开,分别是JVM调优参数.JVM调优方法(流程) ...
- JVM性能调优的6大步骤,及关键调优参数详解
JVM性能调优方法和步骤1.监控GC的状态2.生成堆的dump文件3.分析dump文件4.分析结果,判断是否需要优化5.调整GC类型和内存分配6.不断分析和调整JVM调优参数参考 对JVM内存的系统级 ...
- 直通BAT必考题系列:JVM性能调优的6大步骤,及关键调优参数详解
JVM内存调优 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数. 1.Full GC 会对整个堆进行整理,包括Young.Tenured和Perm.Full GC因为需要对 ...
- JVM 垃圾回收器工作原理及使用实例介绍(转载自IBM),直接复制粘贴,需要原文戳链接
原文 https://www.ibm.com/developerworks/cn/java/j-lo-JVMGarbageCollection/ 再插一个关于线程和进程上下文,待判断 http://b ...
- Java虚拟机内存模型及垃圾回收监控调优
Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存 ...
- 【转】Java学习---垃圾回收算法与 JVM 垃圾回收器综述
[原文]https://www.toutiao.com/i6593931841462338062/ 垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的 ...
- 垃圾回收算法与 JVM 垃圾回收器综述(转)
垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的回收方法.不同回收器的实现细节各有不同,但总的来说基本所有的回收器都会关注如下两个方面:找出所有的存 ...
- JVM垃圾回收器原理及使用介绍
JVM垃圾回收器原理及使用介绍 垃圾收集基础 引用计数法(Reference Counting) 标记-清除算法(Mark-Sweep) 复制算法(Copying) 标记-压缩算法(Mark-Comp ...
随机推荐
- 宜搭5月更新:跨应用数据读写能力升级,AI组件内测开放
简介:表单.权限管理.AI组件等功能上新啦- 本次,我们带来了表单.权限管理.数据管理.平台管理权限.组件等功能的升级. 表单 支持跨应用数据查询 在使用组件数据联动.关联其他表单数据.关联表单组件 ...
- Quick BI产品核心功能大图(五)移动端:让数据在更多业务场景中流通
简介:将数据更好的融入日常工作中,一个重要的前提条件就是多端多渠道的数据触达和办公协同能力. Quick BI凭借移动端交互体验,帮助用户随时随地便捷查看报表,并通过在线协同方式,追踪策略的执行落地 ...
- 钉钉宜搭亮相“第二届ISIG中国产业智能大会”:云钉低代码,构建企业酷应用
简介:低代码年度行业盛会!钉钉宜搭创始人叶周全受邀出席并发表主题演讲. 12月8日,由中国电子技术标准化研究院指导,RPA中国.LowCode低码时代.信创中国联合举办的"第二届ISIG中 ...
- [GPT] Vue 的 methods 中使用了 addEventListener,如何在 addEventListener 的匿名函数参数中访问 Vue data 变量
在 Vue 的 methods 方法中使用 addEventListener时,你可以使用 箭头函数 来访问 Vue 实例的数据. 箭头函数不会创建自己的作用域,而是继承父级作用域的上下文.以下是 ...
- 移动端、微信小程序兼容性问题汇总(持续更新……
1. safari浏览器字体不能自动随网页缩放调整大小 -webkit-text-size-adjust:100% 2. 点击<button><input>有灰色透明背景 -w ...
- 还需要学习JDBC吗?如果需要该了解到怎么样的程度?
前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 不知道大家在工作中还有没有写过JDBC,我在大三 ...
- go1.18泛型全部教程
目录 go1.18泛型全部教程 一 什么是泛型 二 Golang中的泛型 三 泛型语法详解 3.1 泛型的语法 3.2 Constraint(约束)是什么 3.3 自定义constraint(约束) ...
- 使用Elasticsearch在Rails中进行全文本搜索
使用Elasticsearch在Rails中进行全文本搜索 参考: https://blog.csdn.net/cunjie3951/article/details/106921108
- golang基础之结构体
匿名结构体 在定义一些临时数据结构等场景下还可以使用匿名结构体. 在函数体内 package main import ( "fmt" ) func main() { //方法一 v ...
- LVS负载均衡(5)-- LVS持久连接
持久连接: 持久连接用于实现无论使用任何调度算法,在一段时间内(默认300s ),能够实现将来自同一个地址的请求始终发往同一个RS. 语法格式: ipvsadm -A|E -t|u|f service ...