JVM GC调优一则--增大Eden Space提高性能

缘起

线上有Tomcat升级到7.0.52版,然后有应用的JVM FullGC变频繁,在高峰期socket连接数,Cpu使用率都暴增。

思路

思路是Tomcat本身的代码应该是没有问题的,有问题的可能是应用代码升级,或者环境改变了,总之Tomcat的优先级排在最后。

先把应用的heap dump下来分析下:

jmap -dump:format=b,file=path pid

用IBM的Heap Analyser分析,发现dubbo rpc调用的RpcInvocation对象和taglibs的SimpleForEachIterator对象占用了很大部分内存。

正常来说,这两种类型的对象都应该可以很快被回收掉,怎么会占用了那么大的内存空间?是不是有别的对象引用了它们,导致不能释放?

再仔细分析,发现RpcInvocation对象都是root refer的,也就是根对象,正常来说根对象应该可以很快就被回收掉的,为什么在内存中会有那么多对象?

再查看应用的JVM参数:

-Xms2g -Xmx2g -Xmn256m -XX:SurvivorRatio=8 -XX:ParallelGCThreads=8 -XX:PermSize=512m -XX:MaxPermSize=512m -Xss256k -XX:-DisableExplicitGC -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled

首先发现应用的新生代,即-Xmn256m 设置得太小了。对照上面RpcInvocation对象占用了226M,SimpleForEachIterator占用了267M内存。

显然在新生代里,没办法放下那么多的对象,这些对象必然是被放到老生代(old space)里去了。

既然RpcInvocation对象和SimpleForEachIterator对象应该都是可以很快被回收了,那么思路变成,触发一下线上的FullGC,看下对象有没有被回收。

在触发之前,先用jmap -histo pid统计下对象的数量:
  34:        136762        4376384  com.alibaba.dubbo.rpc.RpcInvocation
 129:         16345         392280  org.apache.taglibs.standard.tag.common.core.ForEachSupport$SimpleForEachIterator
用 jmap -histo:live <pid> 触发Full GC之后:
 294:           625          20000  com.alibaba.dubbo.rpc.RpcInvocation
 495:           292           7008  org.apache.taglibs.standard.tag.common.core.ForEachSupport$SimpleForEachIterator
果然数量大大的减少了。

所以结论比较明显了,新生代(Young generation)的空间太小,导致有一些本应该可以很快就被回收的对象被放到了老生代(Old generation)里,导致老生代上涨很快,频繁Full GC。

于是想办法增加新生代的大小,把JVM参数改为:

 -Xms2g -Xmx2g -XX:ParallelGCThreads=8 -XX:PermSize=256m -XX:MaxPermSize=512m -Xss256k -XX:-DisableExplicitGC -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled 

因为观察到PermSize实际上只用了不到200M,没有必要设置为512M,浪费内存,所以改为 -XX:PermSize=256m -XX:MaxPermSize=512m 。

另外,把新生代最大限制-Xmn256m 去掉。因为默认的NewRatio = 2,即除了PermSize,新生代大约占内存的1/3,即约(2048 - 256) /3 = 597M。和原来相比增大了一倍不止。

修改上线之后,观察发现Old Space增长缓慢,FullGC次数大大减少,时间在50ms下,Yong GC都在10ms下,达到了想要的效果。

简单的GC过程分析

首先来看一张GC的模型图,很形象:

简单来说,对于GC,我们了解到这些信息就足够了。

大部分新对象在Eden Space上分配,当Eden Space满了,则要用到Survivor Space来回收。YGC的算法是很快的。

多次YGC之后,还存活的对象就会被移到Old Generation(old space)上,当Old Generation满了的时候,就会FGC,FGC有通常比较慢。

Permanent Space只要你在开始时分配了足够大的空间,那它可以不用管。

我们可以得出一些结论:

  • 合理减少对象进入老生代;
  • Old Space可能会一直增长,有时没有办法避免不让对象进入Old Space,当然也有一些程序是从来都不执行FGC的;
  • 是不是尽全力防止对象进入老生代?显然不是,有些对象如果长久存在在新生代里,显然加重了YGC的负担,多次YGC之后仍然存活的对象显然应该放到Old Space里。

理想的GC/内存使用情况

总结下来,可以发现,理想的GC情况应该是这样的:

Old Space增长缓慢,FullGC次数少,FullGC的时间短(大部情况应该要在1秒内)。

总结:

尽量少加上一些默认参数。这点我很赞同RednaxelaFX的看法,配置了默认参数除了让后面调优的人蛋疼之外,没有太多的帮助。

GC调优就是一个取舍权衡的过程,有得必有失,最好可以在多个不同的实例里,配置不同的参数,然后进行比较。

有很多命令行工具或者图形工具可以使用,好的工具事半功倍。

参考:

http://www.alphaworks.ibm.com/tech/heapanalyzer‎    IBM Heap Analyser

http://hllvm.group.iteye.com/group/topic/27945    JVM调优的"标准参数"的各种陷阱,RednaxelaFX 出品,强列推荐

http://www.taobaotesting.com/blogs/2392      JAVA性能剖析1——JVM内存管理与垃圾回收

http://www.oschina.net/translate/using-headless-mode-in-java-se      在 Java SE 平台上使用 Headless 模式

时间: 2024-09-17 08:11:10

JVM GC调优一则--增大Eden Space提高性能的相关文章

NetApp性能调优:如何不加磁盘提高性能

    Tech OnTap 的读者可能大多都知道,存储系统的随机读取性能在很大程度上取决于硬盘数(存储系统中的硬盘总数)和硬盘转速(单位 RPM).但是,为提高性能而增加硬盘就意味着需要更多的功耗.散热及空间:而且,伴随着硬盘容量增加速度快于其性能表现的提升,很多应用程序可能为了获得最佳性能而要求增加磁盘轴,即便它们并不需要如此大的容量. 在开发性能提高模块(Performance Acceleration Module,简称 PAM)时,NetApp 的目标就是突破随机读取性能和轴数之间的联

优酷土豆资深工程师:GC 调优实战

前情概要 对于线上高并发.高吞吐的Java web服务来说,长时间的GC暂停(也叫 stop- the-world)会严重影响系统吞吐.稳定性和用户体验.下文是我们的一个真实线上web系统针对GC调优过程的一个总结.这个系统在调优前,经常会反映有超秒的GC暂停问题,这种GC问题可能会导致调用方(可能是上层服务调用方.负载均衡层或客户端)阻塞.超时.甚至雪崩的情况.我们在系统资源不变的情况下,经过多轮调优,大幅降低了GC的频率和暂停时间. 前期准备 1.统计应用数据(峰值TPS.平均TPS,每秒平

jvm 怎么调优

JVM性能调优 博客分类: JVM JVM垃圾回收与性能调优总结 JVM调优的几种策略 一.JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从JVM启动参数(-Xmx:3G)指定的内存中分配,Perm不属于堆内存,有虚拟机直接分配,但可以通过-XX:PermSize -XX:MaxPermSize 等参数调整其大小. 年轻代(New):年轻代用来存放JVM

调优servlet和JSP的程序性能

本文讲述了调整JSP和servlet的一些非常实用的方法,它可使你的servlet和JSP页面响应更快,扩展性更强.而且在用户数增加的情况下,系统负载会呈现出平滑上长的趋势.在本文中,我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升.其中,某些调优技术是在你的编程工作中实现的.而另一些技术是与应用服务器的配置相关的.在本文中,我们将详细地描述怎样通过调整servlet和JSP页面,来提高你的应用程序的总体性能.在阅读本文之前,假设你有基本的servlet和JSP的知识. 方法

【JVM】调优笔记2-----JVM在JDK1.8以后的新特性以及VisualVM的安装使用

一.JVM在新版本的改进更新以及相关知识   1.JVM在新版本的改进更新 图中可以看到运行时常量池是放在方法区的 1.1对比: JDK 1.7 及以往的 JDK 版本中,Java 类信息.常量池.静态变量都存储在 Perm(永久代)里.类的元数据和静态变量在类加载的时候分配到 Perm,当类被卸载的时候垃圾收集器从 Perm 处理掉类的元数据和静态变量.当然常量池的东西也会在 Perm 垃圾收集的时候进行处理. JDK 1.8 的对 JVM 架构的改造将类元数据放到本地内存中,另外,将常量池和

【JVM】调优笔记3-----JVM参数配置 JDK1.8

一.关于JVM参数配置,有多种途径. 1.在tomcat中直接配置的 打开tomcat的安装目录, 在bin下修改catalina.bat文件 添加如下: set "JAVA_OPTS=-Xmx300m -Xms300m -Xmn100m -XX:SurvivorRatio=8" 在这个位置: 启动tomcat即可起作用.   2.使用Myecplise,配置JVM参数 双击Tomcat,打开在如下位置,配置: -Xmx300m -Xms300m -Xmn100m -XX:Surviv

【JVM】调优笔记1-----堆栈概念的对碰

关于JVM的工作原理以及调优是一个向往已久的模块,终于有幸接触到:http://pengjiaheng.iteye.com/blog/518623 那就顺着这个思路,来梳理一下自己看到后的结论和感想.   首先,垫些基础,下面会用到 1.Java基本数据类型的长度 类型 字节 表示范围 包装类 byte(字节型) 1 -128~127 Byte short(短整型) 2 -32768-32767  Short int(整型) 4 -2147483648-2147483647 Integer lo

《大规模Java平台虚拟化与调优》——1.3 大规模Java平台的技术因素

1.3 大规模Java平台的技术因素 当设计大规模Java平台时,需要考虑很多的技术因素.例如,对于构建良好的大规模Java平台来说,需要很好地理解Java垃圾回收(garbage collection,GC)以及JVM架构.硬件和hypervisor架构.本节中,概要讨论了GC.非一致内存架构(Non-Uniform Memory Architecture,NUMA),以及在理论和实际操作中的内存限制.稍后的章节会给出更为详细的描述,但首先在整体上理解围绕大规模Java平台设计有哪些问题是非常

调优WebSphere Application Server V7性能

简介 IBM WebSphere Application Server 是一种可靠的企业级应用服务器,它提供了一组核心组件.资源和服务,供开发人员在应用程序中使用.每个应用程序都具备特有的需求,并且经常采用截然不同的方式使用应用服务器的资源.为了提供高度灵活性并支持这种广泛的应用程序,WebSphere Application Server 提供了一组全面的参数来帮助您增强对应用程序的调优. 应用服务器已经为最常用的调优参数设置了默认值,以确保能为最广泛的应用程序提供开箱即用的性能改善.但是,由