引言
内存泄漏的成本非常高昂,经常伴随着产品停机时间和零碎的部署安排。遗憾的是,合适测试解决方案的成本也十分高昂,客户经常不愿意或者不能对必要的资源进行投资。
为了更加清楚起见,解决内存泄漏的最佳方法是在测试时检测并解决它们。理想情况下,应当进行测试安排,并且有一种与产品环境完全相同的测试环境,这种环境能够驱动典型的和异常的工作负载,还应当有技术资源,他们具备专门进行系统测试的适当技能。这是尽可能确保完全转换到产品的最佳方式。但是,设计和提供这样一种环境,以及相关的文化变化,都不是本文的重点。
Java 中有四类常见的内存使用问题:
- Java 堆内存泄漏
- 堆碎片
- 内存资源不足
- 本机内存泄漏。
WebSphere Application Server 已经引入了两种辅助技术,用以帮助客户解决 Java 堆内存泄漏(对这些工具进行一定的扩展还可以解决由于内存资源不足所导致的问题,在本文中没有比较这两种问题的相似性)。
一般来说,当应用程序(由于程序逻辑错误)无意中保存对于不再需要的对象的引用时,会导致 Java 堆内存泄漏。这种无意对象引用阻止内置 Java 垃圾回收机制释放由这些对象所使用的内存。这些内存泄漏的共同原因是:
- 向集合中插入而没有删除
- 未绑定的缓存
- 未调用的侦听器方法
- 无限循环
- 过多的会话对象
- 编写不佳的自定义数据结构。
由于内存资源不足而产生的内存使用问题可能是由于配置问题或系统容量问题所导致的。例如,在为 Java 虚拟机配置最大允许堆大小时所使用的 -Xmx 参数值过低,不能容纳内存中的用户会话总数。或者,系统的物理内存过少,不能容纳当前工作负载。本机内存泄漏是非 Java 代码中的内存泄漏;例如,在 Type-II JDBC 驱动程序或者 Java 进程的地址空间中的非堆段内的碎片。
这是一篇为 Java 开发人员、系统管理员以及问题确定顾问撰写的介绍性文章,这些人员使用部署在 IBM WebSphere Application Server 上的应用程序。
用于检测内存泄漏根源的现有技术中所存在的问题
有大量导致内存泄漏的问题,它们对于系统管理员特别棘手:
-
传统的 Java 内存泄漏根源检测技术有十分显著的性能负担,可能不适于在生产环境中使用。这些技术通常包括堆转储分析、附加 Java 虚拟机分析器接口(Java Virtual Machine Tools Interface,JVMPI)或Java 虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)代理,或者使用字节代码插入来跟踪向集合中的插入和删除。
-
传统的冗余方法,例如群集技术,只能在一定程度上有所帮助。内存泄漏将在群集成员中传播。受影响的应用服务器的响应速度减缓了负载管理技术。这可能导致将请求路由到运行状况更好的服务器,从而导致协调应用服务器崩溃。
一种典型的分析解决方案应当尝试将应用程序移到一个隔离的测试环境中,在这个环境中应当可以重现问题并进行分析,而不会影响生产服务器。由于在这些测试环境中重现问题的难度很大,所以相关内存泄漏的成本增加了。
导致这些问题的原因在于传统技术尝试同时执行检测和分析。
WebSphere 解决方案
WebSphere Application Server V6.0.2 及更高版本提供了一种两阶段解决方案,将 检测 问题与分析 问题分离开来。
第一阶段是轻量级内存泄漏检测机制,运行于生产 WebSphere Application Server 运行时中。这一轻量级检测技术使用成本较低,普遍可用的 Java 堆使用统计数字来监视内存使用趋势,并提供内存泄漏的早期通知。这使管理员有时间准备适当的备份解决方案,并采用离线方式分析问题的根源,而不会存在那些在测试环境中进行重现所导致的问题,这些问题的成本很高,而且也很难解决。
此解决方案的第二阶段是一个脱机工具:Memory Dump Diagnostic for Java (MDD4J),它在生产应用服务器之外分析堆转储。这是一个重量级脱机内存泄漏分析工具,它将多种现有堆转储分析工具整合在单一用户界面中。
为了在检测和分析之间架起一座桥梁,已经为在 IBM JDK 上运行的 WebSphere Application Server 提供了自动化堆转储生成工具。在检测到一种内存泄漏方式之后,此工具将产生多重堆转储,它们可以与足够的内存泄漏进行协调,以方便使用 MDD4J 的对比分析。此外,如果检测到了 OutOfMemoryError,则将 IBM JDK 配置为自动产生堆转储。管理员应当建立负载平衡,或在低使用时间产生堆转储,以避免短时间内性能低下。
|
内存泄漏检测
轻量级内存泄漏检测是通过监视自由内存中的下降趋势而实现的。
泄漏可能非常快速,也可能极其慢,所以短间隔和长间隔的内存使用趋势都会被分析。此外,对于在垃圾收集周期之后近似内存使用中的下降趋势也进行分析,以检测在垃圾收集周期之后平均自由内存数低于特定门限的情况。这样一种情景既可以是内存泄漏的一种标志,也可能表示正在一个资源过少的应用服务器上运行一个应用程序。这一轻量级内存泄漏检测工具可用于从 6.0 版开始的所有 WebSphere Application Server 版本上,并可用于所有平台。
此外,作为 iSeries® 平台的特殊情况,WebSphere Application Server on iSeries 包含一些附加功能,用来检测 Java 堆大小是否要扩展到 DASD上,并将向管理员发出警报,通知管理员是将发生这一现象,还是出现了以下情况之一:
- 有效内存池大小过小
- 资源过少
- 内存泄漏。
zSeries® 在版本 6.0.2 中仅支持单一 Servant 拓扑,但在版本 6.1 中扩展为可以包含多个 Servant 拓扑。在 V6.0.2 中,单一 Servant 拓扑将内存泄漏检测的范围限制为问题确定或测试环境。
图 1 显示了由内存泄漏检测特性所产生的示例通知。这一通知通过 JMX 送出,并显示在管理控制台中,且被记录在服务器日志中。
图 1. 示例内存泄漏通知
自动堆转储生成工具(仅可用在 IBM JDK 上)在内存泄漏的证据非常明显之后、但在应用程序由于 OutOfMemoryError 而崩溃之前产生堆转储。此工具可在足够的内存泄漏之后生成一个第二堆转储。这两个堆转储有助于使用 MDD4J 进行比较分析。
自动堆转储生成可以缺省启用,也可以在适当时间通过 MBean 操作启动。
WebSphere Extended Deployment
尽管在 WebSphere Application Server 和 WebSphere Application Server Network Deployment 中提供了轻量级内存泄漏检测,并且其设计为即时可用,它还是完全可配置的,可以与高级自主管理器或自定义 JMX 客户端交互。WebSphere Extended Deployment 是这种关系的一个例子。
WebSphere Extended Deployment 提供了许多配置内存泄漏检测的策略。一种策略通过取得多个堆转储(使用工作负载管理来维护应用程序的性能)以进行分析,从而对内存泄漏通知做出反应。另一种策略简单地监视应用服务器的内存水平何时达到临界状态,以在应用服务器崩溃之前对其进行重启。
|
内存泄漏分析
一旦已经检测到了内存泄漏并且已经生成了堆转储,它们就可以被传递到生产服务器之外,转到问题确定机器中进行分析。
Memory Dump Diagnostic for Java (MDD4J) 是一种脱机堆转储分析工具,其在确定内存泄漏的根源过程中提供帮助。这一分析机制确定了受怀疑的泄漏数据结构类和数据包。这一标识使系统管理员能够将内存泄漏的根源缩小到有限几个组件应用程序中。
WebSphere Application Server 提供了用于承载来自第三方 J2EE 应用程序的容器。当 Java 堆栈随时间发展时,越来越多的抽象层和组件化被添加到基本 Java 应用程序以及WebSphere Application Server 堆栈中。这样就对发生内存泄漏时进行问题确定造成了巨大的挑战。对于一个遇到内存泄漏的系统管理员来说,承载着大量第三方应用程序的 WebSphere Application Server 就像是一个黑盒。在这种情况下,第一个步骤是将内存泄漏的根源限制到一个或几个组件。根源通常位于一个发生故障的组件应用程序中。在 Memory Dump Diagnostic for Java 工具的分析结果的帮助下,系统管理员现在可以更快速地确定一个错误组件,而不需要来自 IBM 的任何支持。
一旦确定了发生故障的组件,系统管理员可以找到一位开发人员,他能够在更小环境中重现这一问题,并使用调试器或日志记录中的特定跟踪语句来确定错误的源代码方法,并对应用程序代码或者配置进行必要的修改,以解决内存泄漏。有时,了解到故障组件或泄漏对象就足以使我们确定一些常见的配置问题。例如,查找大量的 HTTP 会话对象将会引导我们查看 HTTP 会话超时配置。
这一工具提供的两种主要分析功能是:
-
单一转储分析最经常与内存转储一起使用,它们由 IBM Developer Kit、带有 OutOfMemoryExceptions 异常的Java Technology Edition 自动触发。这一分析类型使用启发式进程来确定受怀疑的数据结构,这些数据结构拥有一个带有大量子对象的容器对象。这一启发式进程对于检测泄漏 Java 集合对象非常有效,这些对象使用一个内部数组来存储所包含的对象。在大量由 IBM Support 处理的内存泄漏案例中,已经发现这一启发式进程非常有效。
-
比较分析用于比较两个在一次运行内存泄漏应用程序期间(也就是当自由 Java 堆内存减少时)所取得的两个内存转储(主转储和基线转储)。比较分析非常适合与轻量级内存泄漏检测一起使用。对于比较分析,主转储表示在已经发生大量内存泄漏时(占用最大配置堆大小的大量内存)所取得转储。基线转储是指当堆尚未因内存泄漏而被大量耗用时早期取得的堆转储。这两个转储之间的堆耗用越大,分析结果就越好。
比较分析技术确定一组大规模数据结构,它们在许多组成数据类型的实例数目方面快速增长。数据结构被分组到每个转储中,然后在主转储和基线转储之间进行匹配与比较,以确定大量增长的可疑数据结构。这一技术不同于当今市场上许多分析工具中可用的基本堆转储区分技术,差别在于,这一技术在更高级别的粒度标识可疑泄漏数据结构,而不是标识泄漏数据类型(例如,粒度级别低很多的字符串)。例如,MDD4J 将告诉您,一个具体容器(例如特定的 EJB 对象)正在泄漏大量字符串,而不是简单地告诉您正在从某一未知源泄漏大量字符串。标识可疑数据结构有助于更好地理解内存泄漏的根源。在图 3 中的树视图中描述了一种示例数据结构,在其中不仅可能看到正在泄漏的字符串对象,而且可以看出它们正被 MyClass 类中的 HashSet引用。
分析结构显示在基于 Web 的交互式用户界面中,其具有以下特性:
-
列出分析结果、堆内容、大小和发展的摘要。
-
列出导致堆使用增长的可疑数据结构、数据类型和数据包,用于比较分析;列出大规模堆,用于单一传储分析。
-
所属权上下文视图显示内存占用空间的主要贡献者与主要内存占用空间贡献者摘要集合的主要组成数据类型之间的所属关系。
-
交互式树视图中的浏览功能显示了堆转储的相关部分,显示对于堆中所有可疑容器对象和该容器对象之所有子对象的所有传入(仅一个显示于树中的引用,其余引用分别显示)和传出引用,它们根据到达大小排序。
-
从可疑列表到所属权上下文和从内容视图再到浏览视图的导航功能。
-
内存转储中所有对象和数据类型的表格式视图,带有筛选器和有序列。
MDD4J 工具将来自许多现有工具的最佳特性组合在一起。比较分析技术基于 Leakbot 研究项目(请参见参考资料)。单一转储分析特性使用的分析技术也可以在 HeapAnalyzer 工具中找到,此工具可以从 alphaWorks 下载(请参见参考资料)。表格式视图基于来自一种命令行工具 HeapRoots 的特性(请参见参考资料)。
使用 WebSphere Application Server V6.1,可以将用于 Java 工具的 Memory Dump Diagnostic (版本 1.0)与 IBM Support Assistant 工具(版本 3.0)一起打包,这是一种独立于 WebSpherer Application Server 单独安装的系统管理员独立工具(请参见参考资料),该工具可以安装在任何计算机上,只要可以将堆转储转换到该计算机上进行脱机分析即可。(有关如何从 Support Assistant 3.0 版 启动 MDD4J 1.0 版的信息,请参见参考资料。)
在下载 IBM Support Assistant 之后,可以利用 Updater 机制单独添加 Memory Dump Diagnostic for Java:在 IBM Support Assistant 中,选择Updater 视图中的 New Products and Tools => Common Component and Tools(还请确保已经安装了 WebSphere Application Server V6.0 或 V5.0 产品插件)。
相对于以前版本(版本 0.97a),MDD4J(版本 1.0)的这一新版本的特性具有许多与可伸缩性有关的改进,并且支持 64 位堆转储。(MDD4J 的这一先前版本可以作为技术预览 developerWorks 下载,请参见参考资料。)
下面的示例显示了对于简单内存泄漏 Java 应用程序的内存泄漏分析结果。这一示例应用程序将字符串对象泄漏到一个静态 HashMap 中。轻量级泄漏检测能够确定早期泄漏的出现,并自动产生适当的堆转储。然后,使用 Memory Dump Diagnostic for Java Version 1.0 中的比较分析对这些转储进行脱机分析。显示内存泄漏疑点的分析结构显示在图 2、图 3 和图 4 中。
图 2. Memory Dump Diagnostic for Java 分析结果中的内存泄漏疑点。
图 3. 在 Memory Dump Diagnostic for Java 中浏览可疑数据结构
图 4. Memory Dump Diagnostic for Java 分析的内存占用空间分析
结束语
使用 WebSphere Application Server V6.1,系统管理员能够在其生产环境中接收关于内存泄漏的早期通知,而不必使用字节代码插入或任何附加代理。已经设计了轻量级内存泄漏检测,其可以将对性能的影响降至最低,并提供在适当时间自动生成堆转储的功能,以确保正确的分析结果。
可以使用 Memory Dump Diagnostic for Java (MDD4J) 以脱机方式分析手动生成或者在内存泄漏检测的帮助下生成的堆转储。这一工具可以帮助系统管理员将问题限制到到适当的组件,开发人员可以在其计算机上很容易地重现分析结果。MDD4J 为开发人员和问题检测顾问提供了一种工具,用以确定泄漏怀疑对象,浏览堆和所属权链,以确定其代码中的什么数据结构正在泄漏。
这一技术非常有助于诊断 Java 堆内存泄漏并对其进行分析,既可用于良好的系统测试过程,也可用于生产系统。
|
致谢
本文作者向以下各位表示感谢:感谢 Daniel Julin 和 Stan Cox 审阅本文;感谢 LeakBot 项目的首席研究员 Nick Mitchell 的领导和创新;感谢 Mark T Schleusner 在开发 MDD4J 过程中的帮助和协作。
文章来源于领测软件测试网 https://www.ltesting.net/
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备2023014753号-2
技术支持和业务联系:info@testage.com.cn 电话:010-51297073