JVM性能调优

原文地址:http://blog.csdn.net/kuyuyingzi/article/details/20149241

主要是为了方便自己以后查找相关的知识

1:新生代串行收集器:(默认收集器)

     算法:复制算法
     -XX:+UseSerialGC 指定使用新生代 串行收集器和老年代 串行收集器
     优点:效率高,久经考验
     缺点:串行,如果回收对象过多,或者堆过大,停顿时间会过长。

2:老年代串行收集器(cms收集器的备选)
     算法:标记-压缩算法
     -XX:+UseSerialGC:指定新生代 串行收集器和老年代 串行收集器
     -XX:+UseParNewGc:新生代使用 并行收集器和老年代使用 串行收集器
     -XX:+UseParallelGc:新生代使用 并行回收收集器和老年代使用 串行收集器


3:并行收集器
     算法:复制算法
     工作在新生代的垃圾收集器,简单的将串行回收器多线程化,策略和串行一样。也是独占式的。在多cpu环境下会比串行收集器好,停顿时间短。
     -XX:+UseParNewGC:新生代使用 并行收集器,老年代使用 串行回收器
     -XX:+UseConcMarkSweepGC:新生代使用 并行收集器,老年代使用 cms

     线程数量:
     -XX:ParallelGCThreads指定,一般最好与cpu数量相当。cpu小于8个时和cpu数量一样,cpu大于8个时 3+[(5*cpu/8)]

4:新生代并行回收收集器(Parallel Scavenge)
     算法:复制算法
     和并行收集器一样,区别在于这个收集器关注系统吞吐量
     -XX:+UseParallelGC:新生代使用并行回收收集器,老年代使用串行收集器
     -XX:+UseParallelOldGC:新生代和老年代都使用并行回收收集器

     吞吐量设置:
     -XX:MaxGCPauseMillis:设置停顿时间不超过多少。大于0的整数,收集器会调整对的大小或者其他一些参数,使得垃圾收集停顿时间控制在设置的时间

     -XX:GCTimeRatio:设置吞吐量大小,0~100之间的整数 公式:1/(1+n),系统将花费不超过这个时间来用于垃圾收集。

     -XX:useAdaptiveSizePolicy:打开自适应gc策略,新生代大小,eden和servivor的比例,晋升老年代的对象年龄都会自动调整以达到对大小,吞吐量和停顿时间之间的平衡。

5:老年代并行回收收集器
     算法:标记压缩算法
     和新生代并行回收器一样,它也是一种关注吞吐量的收集器

     -XX:+UseParallelOldGC:新生代和老年代都使用并行回收收集器


6:cms收集器
     算法:标记-清除算法
     和并行回收收集器的区别是:注重系统停顿时间
     
     工作步骤:
  •      初始标记:独占资源
  •      并发标记:非独占资源
  •      重新标记:独占资源
  •      并发清除:非独占资源
  •      并发重置:非独占资源
     -XX:ParallelGCThreads:设置cms的线程数量,默认启动线程数是:(ParallelGCThreads+3/4)
     -XX:CMSInitiatingOccupancyFraction:设置当老年代空间实用率达到百分比值时进行一次cms回收

     因为使用标记清除算法,所以长时间后会有碎片产生
     -XX:+UseCMSCompactAtFullCollection:设置cms在垃圾收集完成后进行一次内存碎片整理
     -XX:CMSFullGCsBeforeCompaction:设定进行多少次cms回收后,进行一次内存压缩。

     应为cms不停止应用程序,所以在cms回收过程中,可能因为内存不足而导致回收失败,失败的话会启动 老年代串行收集器进行垃圾回收,这样应用程序将完全中断,这时停顿时间可能会很长。可以通过设置-XX:CMSInitiatingOccupancyFraction来解决


7:G1收集器(garbage first) jdk1.6update14才提供预览版,jdk1.7才发布






总结:
     在众多的垃圾回收器中,没有最好的,只有最适合应用的回收器,根据应用软件的特性以及硬件平台的特点,选择不同的垃圾回收器,才能有效的提高系统性能。


jvm调优思路与方法:

1:将新对象预留在新生代
     一般来说,当survivor区空间不够,或者占用量达到50%时,就会将对象进入老年代(不管对象年龄有多大)

2:大对象进入老年代
     开发中要避免短命的大对象,目前没有特别好的方法回收短命大对象,大对象最好直接进入老年区,因为大对象在新生区,占用空间大,会由于空间不足而导致很多小对象进入到老年区。
 -XX:PretenureSizeThreshold:设置大对象直接进入老年代的阈值,当对象的大小超过这个值将直接分配在老年代

3:设置对象进入老年代 的年龄:
  -XX:MaxTenuringThreshold:设置对象进入老年代的年龄,默认值时15,但是如果空间不够,还是会将对象移到老年代。

4:稳定与震荡的堆大小

     稳定的堆大小能减少gc次数,但是每次gc时间增加
     震荡的堆大小能增加gc次数,但是每次gc时间减少

     -XX:MinHeapFreeRatio:最小空闲比例,当堆空间空闲内存小于这个比例,则扩展
     -XX:ManHeapFreeRatio:最大空闲比例,当堆空间空闲内存大于这个比例,则压缩

     -Xms和-Xmx相等时,上面的参数失效


5:吞吐量方案:
     4G内存32核吞吐量优先方案:尽可能减少系统的执行垃圾回收的总时间,考虑使用关注吞吐量的并行回收收集器。
     -Xms:3800 
     -Xmx:3800
     -Xss:128k //减少线程栈大小,使剩余系统内存支持更多线程
     -Xmn:2g //设置新生代大小
     -XX:UseParallelGC:新生代并行回收收集器
     -XX:ParallelGCTHreads:设置线程数
     -XX:+UseParallelOldGC:老年代也使用并行回收收集器
     

6:使用大页案例
      -Xmx:2506 
     -Xms:2506
     -Xss:128k //减少线程栈大小,使剩余系统内存支持更多线程
     -XX:UseParallelGC:新生代并行回收收集器
     -XX:ParallelGCTHreads:20
     -XX:+UseParallelOldGC:老年代也使用并行回收收集器
     -XX:LargePageSizeInBytes=256m


7:降低停顿案例:
   降低停顿首先考虑的是使用关注系统停顿的cms回收器,其次为了减少fullgc次数,应尽可能将对象预留在新生代,因为新生代minorgc的成本远小于老年代的fullgc

     -Xms:3550
     -Xmx:3550
     -Xss:128k //减少线程栈大小,使剩余系统内存支持更多线程
     -Xmn:2g //设置新生代大小
     -XX:ParallelGCThreads:20
     -XX:+UseConcMarkSweepGC //老年代使用cms回收器
     -XX:+UseParNewGC //新生代使用并行回收器
     -XX:SurvivorRatio=8 //设置eden和survivor比例为8:1
     -XX:TargetSurvivorRatio=90 //设置survivor使用率
     -XX:MaxTenuringThreshold=31 //年轻对象进入老年代的年龄,默认是15,这里是31


下面是一次成功的案例。

原文链接:http://bbs.csdn.net/topics/310110257

JVM基础:可以学习《编写高质量写代码》建议137:调整JVM参数以提升性能一节


JVM参数调优是个很头痛的问题,设置的不好,JVM不断执行Full GC,导致整个系统变得很慢,网站停滞时间能达10秒以上,这种情况如果没隔几分钟就来一次,自己都受不了。这种停滞在测试的时候看不出来,只有网站pv达到数十万/天的时候问题就暴露出来了。


要想配置好JVM参数,需要对年轻代、年老代、救助空间和永久代有一定了解,还要了解jvm内存管理逻辑,最终还要根据自己的应用来做调整。关于JVM参数上网一搜就能搜出一大把,也有很多提供实践的例子,我也按照各种例子测试过,最终还是会出现问题。

经过几个月的实践改善,我就网站(要求无停滞时间)的jvm参数调优给出以下几条经验。

1:建议用64位操作系统,Linux下64位的jdk比32位jdk要慢一些,但是吃得内存更多,吞吐量更大。

2:XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可以减轻伸缩堆大小带来的压力。

3:调试的时候设置一些打印参数,如-XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log,这样可以从gc.log里看出一些端倪出来。

4:系统停顿的时候可能是GC的问题也可能是程序的问题,多用jmap和jstack查看,或者killall -3 java,然后查看java控制台日志,能看出很多问题。有一次,网站突然很慢,jstack一看,原来是自己写的URLConnection连接太多没有释放,改一下程序就OK了。

5:仔细了解自己的应用,如果用了缓存,那么年老代应该大一些,缓存的HashMap不应该无限制长,建议采用LRU算法的Map做缓存,LRUMap的最大长度也要根据实际情况设定。

6:垃圾回收时promotion failed是个很头痛的问题,一般可能是两种原因产生,第一个原因是救助空间不够,救助空间里的对象还不应该被移动到年老代,但年轻代又有很多对象需要放入救助空间;第二个原因是年老代没有足够的空间接纳来自年轻代的对象;这两种情况都会转向Full GC,网站停顿时间较长。第一个原因我的最终解决办法是去掉救助空间,设置-XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0即可,第二个原因我的解决办法是设置CMSInitiatingOccupancyFraction为某个值(假设70),这样年老代空间到70%时就开始执行CMS,年老代有足够的空间接纳来自年轻代的对象。

7:不管怎样,永久代还是会逐渐变满,所以隔三差五重起java服务器是必要的,我每天都自动重起。

8:采用并发回收时,年轻代小一点,年老代要大,因为年老大用的是并发回收,即使时间长点也不会影响其他程序继续运行,网站不会停顿。

我的最终配置如下(系统8G内存),每天几百万pv一点问题都没有,网站没有停顿,2009年shedewang.com没有因为内存问题down过机。

$JAVA_ARGS .= " -Dresin.home=$SERVER_ROOT -server -Xms6000M -Xmx6000M -Xmn500M -XX:PermSize=500M -XX:MaxPermSize=500M -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0 -Xnoclassgc -XX:+DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=90 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log ";

说明一下, -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0就是去掉了救助空间;
-Xnoclassgc禁用类垃圾回收,性能会高一点;
-XX:+DisableExplicitGC禁止System.gc(),免得程序员误调用gc方法影响性能;
-XX:+UseParNewGC,对年轻代采用多线程并行回收,这样收得快;
带CMS参数的都是和并发回收相关的,不明白的可以上网搜索;
CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn就不会出现promotion failed。在我的应用中Xmx是6000,Xmn是500,那么Xmx-Xmn是5500兆,也就是年老代有5500兆,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还剩10%的空间是5500*10%=550兆,所以即使Xmn(也就是年轻代共500兆)里所有对象都搬到年老代里,550兆的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的promotion failed;
SoftRefLRUPolicyMSPerMB这个参数我认为可能有点用,官方解释是softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap,我觉得没必要等1秒;

网上其他介绍JVM参数的也比较多,估计其中大部分是没有遇到promotion failed,或者访问量太小没有机会遇到,(Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100>=Xmn这个公式绝对是原创,真遇到promotion failed了,还得这么处理。


注意了,解决停滞问题就是用UseParNewGC+CMS,解决promotion failed问题就是加大救助空间、加大年老代空间、设置CMSInitiatingOccupancyFraction。  

64位jdk似乎不能设置MaxTenuringThreshold,一旦设置MaxTenuringThreshold=0,CMS也有停滞。  

所以64位jdk参考下面这个设置,年老代涨得很慢,CMS执行频率变小,CMS没有停滞,也不会有promotion failed问题,内存回收得很干净。不过还是要灵活配置才行,只要理解了,总能找到适合自己应用的解决办法。 

$JAVA_ARGS .= " -Dresin.home=$SERVER_ROOT -server -Xmx3000M -Xms3000M -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=70 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log ";


又有改进了,上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS执行会比较频繁。我改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有promotion failed。

具体操作上,32位Linux和64位Linux好像不一样,64位系统似乎只要配置MaxTenuringThreshold参数,CMS还是有暂停。为了解决暂停问题和promotion failed问题,最后我设置-XX:SurvivorRatio=1 ,并把MaxTenuringThreshold去掉,这样即没有暂停又不会有promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以CMS执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。

下面是64位的配置,系统8G内存。
-Xmx4000M -Xms4000M -Xmn600M -XX:PermSize=500M -XX:MaxPermSize=500M -Xss256K -XX:+DisableExplicitGC 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值