概述
在说尝试调优之前,我们先简单介绍一下heap堆,我们知道heap堆是为了存放对象的,所以,介绍heap也要介绍一下heap中对象。
从上一篇分析gc信息,我们总结了,做gc调优目标,就是减少gc频率和耗时,以及减少程序暂停时间
(一)、首先简单了解一下heap内存堆
年轻代:所有新生成的对象首先都是放在年轻代的。年轻代分三个区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
年老代:在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
持久代:用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。
堆大小定义如下:
总heap大小定义参数是:
默认是物理内存的1/64但小于1G。
-Xmx(最大堆大小)
-Xms(最小堆大小)
年轻代大小定义参数:
-Xmn(年轻代大小)
-XX:NewRaito(设置年轻代和年老代的比例值)
-XX:SurvivorRaito(设置年轻代中Eden区与Survivor区的比值,如此值为4,则Eden为4/6,两个Survivor分别为1/6)
持久代大小定义参数:
-XX:PermSize(启动时候持久代大小)
-XX:MaxPermSize(持久代最大可占用大小)
没有特定设置年老代大小的参数,其实可以计算得到。年老代=heap总大小-年轻代-持久代
(二)、对象移动规则
当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”,所以年轻代对象到达年老代规则:
1. 经历多次minor gc仍存活的对象,可通过MaxTenuringThreshold=<N>参数来控制,默认为15。
2. 对象在to space区放不下,就会直接放入旧生代
(三)、简单了解各个区的gc
我们从上面知道,heap内存堆分为三大区,每个区域都有自己的gc方式,请看下面表
| 年轻代 | 年老代 | 持久代 | |
GC类型 | YGC | FGC | ||
触发条件 | 当eden空间已满时触发 | 年老代空间不足 调用System.GC, RMI等的定时触发 | 持久代空间不足 | |
触发事件 | 清空Eden+from survivor中所有no ref的对象占用的内存将eden+from sur中所有存活的对象copy到to sur中; 重新调整Eden 和from的大小(parallel GC会触发此项) | 清空heap中no ref的对象 | ||
串行 | 适用环境 | 适用于单CPU、新生代空间较小及对暂停时间要求不是非常高的应用上,也是client级别(CPU核数小于2或物理内存小于2GB)或32位Windows机器上默认采用的GC方式 | ||
设置参数 | 通过参数-XX:+UseSerialGC指定 | |||
并行 | 适用环境 | 适合于多CPU、对暂停时间要求较短的应用上。并行回收GC是server级别(CPU核数超过2且物理内存超过2GB)的机器(32位Windows机器除外)上默认采用的GC方式 | ||
设置参数 | 通过-XX:+UseParallelGC来指定 | 可通过-XX:+UseParallelGC或-XX:+UseParallelOldGC来强制指定 并行的线程数cpucore<=8 ? cpucore : 3+(cpucore*5)/8或通过-XX:ParallelGCThreads=<N>来强制挃定。 | ||
并发 | 适用环境 | GC须配合旧生代使用CMS GC,CMS GC在进行旧生代GC时,有些过程是并发进行的 | ||
设置参数 | 在配置为使用CMS GC的情况下,通过-XX:+UseParNewGC来指定; | -XX:+UseConcMarkSweepGC来启用CMS进行旧生代对象的GC;并发的线程数默认为:( 并行GC线程数+3)/4,也可通过ParallelCMSThreads=<N>指定 | -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled |
(四)、尝试调优
根据第二章 分析gc信息,我们知道gc调优5个目标就是:
1、 降低Full GC执行频率
2、 降低Full GC消耗时间
3、 降低Full GC所造成的应用暂停时间
4、 降低Minor GC执行频率
5、 降低Minor GC消耗时间
那么如果做呢?
步骤:
1、 评估一下gc现状,看它是否以及满足期望值,比如gc频率大于10秒,gc耗时小于500毫秒,暂停应用系统时间每次不到200毫秒,如果是这样,那么我们认为gc调优结束,不用走第二步了
2、 分析gc,根据gc调优目标,找出不符合目标的情况,使用不同方法调试。
| 可能出现情况 | 分析与措施 |
降低Full GC执行频率 | Java RMI的定时GC触发 | 程序调用了system.gc 通过:-XX:+DisableExplicitGC来禁止 |
Minor GC后总是有对象不断的进入年老代,导致年老代不断的满 | Survivor太小了系统响应太慢、请求量太大、每次请求分配内存多、分配的对象太大 1、扩大年老代大小(减少年轻代或调大heap);减少年轻代注意对minor gc的影响并且同时有可能造成fullgc还是严重;调大heap注意full gc的时间的延长,cpu要求够多或者处理能力强。 2、程序优化(去掉一些不必要的缓存) | |
Minor GC后总是有对象不断的进入年老代,而且这些进入年老代的对象在full时大部分都会被回收 | 1、降低Minor GC执行频率(看下面) 2、让对象尽量在Minor GC中就被回收掉:放大年轻代、放大survivor、增大TenuringThreshold但要注意这些有可能会造成minor gc执行频繁 3、换CMS GC :年老代还没满就回收掉,从而降低Full GC触发的可能 4、程序优化:提升响应速度、降低每次请求分配的内存 | |
降低Full GC消耗时间 | 年老代太大了 | 1、改为并行GC,或者并发GC 2、减小Heap或旧生代吧 3、增加cpu |
降低Full GC所造成的应用暂停时间 |
| 修改gc策略 |
降低Minor GC执行频率 | 每次请求分配的内存多、请求量大 | 1、 扩大heap、 2、 扩大年轻代代、扩大eden, 3、 横向集群部署应用程序 扩大时请综合考虑;降低每次请求分配的内存; |
降低Minor GC消耗时间 | 1、新生代太大了 2、响应速度太慢了,导致每次Minor GC时存活的对象多 | 1、 减小点新生代吧; 2、 增加CPU吧或者升级CPU吧; |
最后
以上就是过时御姐为你收集整理的GC调优方案,步骤三:尝试调优的全部内容,希望文章能够帮你解决GC调优方案,步骤三:尝试调优所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复