简单 • 快乐 • 测试

内存泄露分析(转)

上一篇 / 下一篇  2011-09-09 09:54:39 / 个人分类:性能测试工具

1、首先是测试人员使用Loadrunner测试的过程中发现系统的吞吐率会随着时间而下降,在排除了测试数据分布不均的问题在测试,发现吞吐率保持稳定的一段时间后会陡然下降,平均事务处理时间陡然上升。于是,对系统的运行进行监控,在客户端压力平均的时候,系统内存两个小时内从500m上升到1G,基本上可以认定是内存泄露。
1.1系统的吞吐率图
440a522a-7b42-4aa2-9a2c-f703267b9ac9.jpg

1.2系统的平均事务处理时间图

2bb1198b-25de-4e3b-8423-bce2740168ee.jpg
2、添加 verbose:gc启动的参数,重新测试,发现每次Full GC后的对象空间持续缓慢增加,过了一段时间后,发现Miner GC无法释放空间,每次GC都是Full GC,到最后,Full GC也无法释放出空间出来。


3、安装netbean profile对系统使用情形进行监控,发现
a、堆内存的已使用空间缓慢增长,直到最大内存限制;

cb10e4c6-1328-42b5-ab06-43c289d7cab8.jpg
b、接近最大内存限制的时候,内存平均对象的年龄(Surviving Generations)急剧上升,见下图中的红线。
c、Relative Time Spendt in GC 直剧上升,分析,当GC占用的CPU大量时间,系统的吞吐率下降,和LoadRunner的测试结果是符合的。见下图中的蓝线

06cdfd35-2b87-4cf7-913e-baac371ebfe2.jpg

4、获取内存对象的静态映像,发现内存中占空间最大的几种存活对象的平均对象年龄都比较大,并且随着时间的增长,这几类对象占用的空间与平均对象年龄都不停的加大,见图。

3b386108-3fd2-4909-9d09-24b15267ac01.jpg

5、查看这几种对象的分配时候的程序堆栈,发现这些对象是mule框架初始化组件对象的时候所创建,心中犯疑,什么促使mule框架不停的创建全局对象?
33b6da44-5d9a-4a99-9f02-c462ff3dd416.jpg
追踪了几条对象生成的路径,发现不断增长的对象似乎都是 org.mule.providers.soap.xfire.transport.MuleLocalTransport产生的,例如,19m的 HashMap$Entry[]由MuleLocalTransport的父类 org.codehaus.xfire.transport.AbstractTransport构造的时候产生,17m的 HashMap$Entry[]由MuleLocalTransport的createNewChannel的方法生成。每调用 createNewChannel一次就会生成一个全局对象 org.codehaus.xfire.transport.DefaultEndpoint。而MuleLocalTransport对象只有在初始化的时候才会生成全局对象。继续看代码发现可以在XFireServiceComponent的setDescriptor打印日志来确认mule是否不停创建全局对象。

6、在XFireServiceComponent的关键初始化方法setDescriptor中添加日志,编译、重新打包,替换原来的类。新的类每当 setDescriptor被调用一次就打印一行日志。重新测试,发现每个一段时间setDescriptor就被调用一次。由于每调用 setDescriptor一次,就会产生大量的全局对象,并且全局对象不被释放,导致堆内存的增长。

7、会让mule如此疯狂的原因是什么呢?详细查看mule的配置,逐步集中到对象池与线程池的配置:发现对象池的配置maxActive=5,maxIdle=5 <pooling-profile maxactive="5" maxidle="5" exhaustedaction="GROW" maxwait="1000">,配置明显过小,在对象池的exhaustedAction="GROW" 。线程池的配置maxThreadsActive明显大于对象池的配置。这样mule肯定会创建对象,由于</pooling- profile> 对象池的对象很快由于超过了maxActive=5,多余的对象会被释放。
<pooling-profile maxactive="5" maxidle="5" exhaustedaction="GROW" maxwait="1000">
8、修改该配置maxActive=50,maxIdle=50,</pooling-profile> 对象池的exhaustedAction="Wait", <pooling-profile maxactive="5" maxidle="5" exhaustedaction="GROW" maxwait="1000">重新运行,</pooling-profile> maxThreadsActive=50 <pooling-profile maxactive="5" maxidle="5" exhaustedaction="GROW" maxwait="1000">。是运行了7个小时,内存正常。

9、由于</pooling-profile> 对象池的exhaustedAction="Wait"的情况下没有内存泄露,不等于说mule没有问题。mule放入对象池的对象是DefaultMuleProxy。为了与xfire集成,对象池放入一类特殊对象:
org.mule.impl.model.DefaultMuleProxy -〉org.mule.providers.soap.xfire.XFireServiceComponent
后者包含成员变量org.mule.providers.soap.xfire.transport.MuleLocalTransport与 org.mule.providers.soap.xfire.transport.MuleUniversalTransport在对象池释放 DefaultMuleProxy后没有得到释放。从netbeans profile的内存映像上看:这两个类的对象,生成对象的数目==存活的对象数目,一个都没有释放过。这两类对象又携带了大量的全局对象,导致内存泄露。

10、上述两类对象为什么无法释放?经过一番查找,发现在XFireServiceComponent的setDescriptor方法,对象被注册到 org.codehaus.xfire.transport.DefaultTransportManager中去了,之后不见有unregister的操作。代码如下:
        getTransportManager().register(transport);
        getTransportManager().register(universalTransport);

TAG: 性能测试 性能分析 LoadRunner 内存泄露 瓶颈定位 loadrunner

 

评分:0

我来说两句

另一种蓝

另一种蓝

我认为酒一口一口喝,路一步一步走! 步子迈大了,容易扯着蛋。

日历

« 2024-03-23  
     12
3456789
10111213141516
17181920212223
24252627282930
31      

数据统计

  • 访问量: 39309
  • 日志数: 22
  • 建立时间: 2009-09-21
  • 更新时间: 2014-12-18

RSS订阅

Open Toolbar