LoadRunner主要通过性能计数器来监控系统资源。
步骤1添加监控计数器
在Controller的运行视图中,添加需要监控的性能计数器。
操作系统级内存计数器(Windows示例)
计数器对象Memory,计数器Available Mbytes:可用物理内存。这是最直观的标准,不断下降是泄漏的强烈信号。
计数器对象Memory,计数器Pages/sec:每秒页错误数。不断过高可能表示内存压力大,导致频繁磁盘交换。
计数器对象Process,计数器Private Bytes:所选进程分配的独占内存量。监控被测应用进程的此值是不是不断增长是重点。
计数器对象Process,计数器Working Set:进程工作集大小,即物理内存占用。
应用服务器级计数器(以Java为例)
需保证JVM已启用 JMX 监控。
java.lang:type=Memory:
HeapMemoryUsage.used:堆内存已使用量。
NonHeapMemoryUsage.used:非堆内存使用量。
*java.lang:type=GarbageCollector,name= **:
CollectionCount:垃圾回收次数。
CollectionTime:垃圾回收累计时间。
数据库级计数器
监控数据库连接池的使用情况,连接不释放也会导致内存泄漏。
步骤2配置监控和执行测试
在设计视图中,保证场景负载模型是不断性或循环递增的,便观察内存随时间的变化。
设置足够的测试运行时间。内存泄漏一般需要较长时间(如30分钟以上)才能明显暴露。
执行情形,并实时观察添加的计数器图表。
步骤3在Analysis中深入分析数据
测试完成后,使用 Analysis 组件进行深度分析。
整合图表:
将可用内存(Available Mbytes)、被测进程的私有字节(Process(YourApp)\Private Bytes) 和运行用户数(Running Vusers)、事务响应时间(Transaction Response Time)叠加在同一个图形中。
进行关联分析:
正常方式:负载(用户数)上升时,内存占用上升;负载下降时,内存占用应显著回落。
泄漏方式:负载回落后,内存占用不回落或仅回落一小部分,且下一次负载峰值时,内存起点比上一次更高,形成台阶式上升。
聚焦GC活动:
分析 GarbageCollection 相关的计数器。如果发现CollectionCount(特别是Full GC)在测试后期异常频繁,且CollectionTime大幅增加,同时HeapMemoryUsage.used基线不断上移,这几乎可以确定是堆内存泄漏。
诊断排查建议
隔离和定位:
一旦通过LoadRunner宏观定位到内存泄漏,一般需要借助更专业的剖析工具(Profiler) 进行代码级诊断,如:Java VisualVM、JProfiler、.NET Memory Profiler 或 Valgrind(C/C++)。
在Profiler中,重点查找支配树或保留堆分析,找出哪些对象实例数量异常多且无法被回收。
LoadRunner脚本排查:
检查Vuser脚本中是不是存在连接(数据库、网络、文件)未正确关闭的情况。
检查参数化或动态数据使用是不是正确,防止数据无限累积。
流程
基线测试:先运行一个短时间的标准测试,记录正常情况下的内存使用方式。
耐力测试:设计一个长时间(如8-24小时)的稳定负载情形,这是发现内存泄漏的最好测试类型。
监控配置:系统性地添加操作系统、中间件、数据库三层的重点内存计数器。
方式比对:在Analysis中,重点比对内存消耗曲线和负载曲线的走势关系。内存曲线和负载曲线背离(负载稳定,内存不断增长)是判断根据。
结合日志:将LoadRunner结果和应用服务器的GC日志、错误日志时间点进行关联分析,能获得更确切的证据。