<% if session("name")<>"" then response.write("当前用户:"&session("name")) response.write("  注销") response.write("  修改资料") else if request.cookies("name")<>"" then response.write("当前用户:"&request.cookies("name")) response.write("  注销") response.write("  修改资料") end if end if %>
首页 >经验与观点>应用性能管理 >提高Java开发质量之"内存泄露"

应用性能管理

 
  • 在服务器端进行数据库审计的优势
  • 服务器端审计工具与所谓非侵入性审计工具的比较
  • 如何提升运维管理
  • ITIL提升中国电信运维管理系统建设
  • 提高Java性能的几个高效用法
  • 提高J2SE性能的代码技巧(上)
  • 提高J2SE性能的代码技巧(下)
  • 应用管理的概念和流程
  • 应用管理的运营和优化
  • 开源时代:Navicat实现从MS SQL到MySQL的数据迁移
  • 使用Navicat导入数据到MySQL
  • 单元测试中贯彻持续性能管理
  • 单元测试性能分析报告
  • 利用Hyperic HQ管理WebLogic
  • Hyperic HQ监测Linux系统10条最佳成功经验
  • 什么是服务等级管理
  • 服务等级管理的步骤
  • 服务等级管理中的关键控制要素
  • 服务等级管理中需要注意的几个问题
  • 什么是容量管理
  • 容量管理的几个重要环节
  • 容量管理中的关键控制要素
  • 容量管理中需要注意的几个问题
  • 持续性能管理的先决条件
  • SQL Server调优的五个步骤(上)
  • SQL Server调优的五个步骤(下)
  • J2EE性能问题的分析
  • J2EE性能问题的诊断
  • J2EE性能问题的诊断示例
  • 应用性能管理-从操作系统做起
  • SQL Server常见性能问题的优化
  • 应用性能管理(APM)的价值分析
  • Bea WebLogic Portal的性能监测和诊断
  • 数据库性能基准的五个问题
  • Portal的性能挑战
  • 在多种数据库环境下管理业务需求(下)
  • Oracle DBA如何管理DB2(下)
  • 在多种数据库环境下管理业务需求(上)
  • Oracle DBA如何管理DB2(上)
  • SQLServerSQL调优技巧
  • 诊断应用数据库的性能瓶颈
  • Oracle优化的五个方面
  • Microsoft的优化SQL方法
  • 理解SQL Server的SQL查询计划
  • 自动化性能测试
  • 优化应用质量和性能,支持和推动业务发展
  • 从PMO到CIO办公室—PMO的发展趋势
  • 实施自动化功能测试的解决方案
  • 软件自动化测试流程
  • 测试自动化的成功经验
  • 无计划的变化导致的IT风险
  • 降低无计划的变化导致的IT风险
  • 应用性能管理中的价值链分析
  • 应用系统"亚健康"的严重性
  • 应用系统"亚健康"现象和原因
  • 性能测试的准备
  • 性能测试的六个阶段
  • 性能测试的容量评估
  • 优化DB2数据库的十个最佳实践
  • 优化DB2数据库的十个最佳实践(续)
  • 在生产中监测和优化J2EE应用性能
  • 改善J2EE性能和用户体验的管理变革
  • 跟踪数据库性能变化
  • 优化ERP应用
  • 在生产中测量J2EE应用性能
  • Oracle SQL性能优化技巧1
  • Oracle9i查询优化工具初探
  • APM的方法和技术实现
  • J2EE性能问题的症状和优化
  • 构造高性能J2EE应用10个技巧
  • 软件工程与知识管理

     
  • 采用CASE工具管理多个并行应用软件开发项目
  • "软件工程"中的分工有效吗?
  • 实施知识管理软件的几个细节
  • 拯救知识管理
  • 知识管理与知识管理软件
  • IT培训师指要
  • 推荐产品的使用

     
  • Toad快速入门
  • PerformaSure J2EE性能诊断
  • PerformaSure J2EE健康检查示例
  • Spotlight实时诊断WebSphere Server实践
  • Spotlight实时诊断WebLogic Server实践
  • JProbe实践之"性能瓶颈"
  • JProbe实践之"短期对象循环"
  • JProbe实践之"内存泄露"
  • JProbe实践之"代码覆盖"
  • Quest Jprobe最佳实践(上)
  • Quest Jprobe最佳实践(下)
  • Foglight-APM与SLA的有力武器





  • 提高Java开发质量之"内存泄露"

                ---Quest JProbe实践之一

         当前,J2EE的开发质量的问题已经越来越突出,如果你的即将上线或已经上线的应用经常不稳定,特别在负载大时尤为明显,你经常忙于在最后时刻救火,那么应该考虑在开发的早期尽量进行性能方面的测试。本文将探讨在J2EE开发中,常见的解决办法,这里以Quest JProbe Suite 工具为例,说明在实际开发中应如何提高开发质量。

         "内存泄露"是目前Java应用中最为常见的问题之一,单元测试的不完善直接导致生产系统的不稳定。单元测试是解决"内存泄露"问题的比较适当的环节。这样可以避免在生产系统中进行冗长烦琐的搜集数据和分析工作。

         "内存泄露"简单地说,开发人员主观认为已经不再使用,而实际上在 JVM中仍然被使用的那些对象。往往是由于开发人员的疏忽、架构设计的问题或所使用第三方组件的瑕疵等造成的。

         这里我们使用Quest JProbe 来分析一个简单的用例。

         如下面三图所示,点击Add按钮十次,增加0-9个 Button(如第二图),然后点击 Remove按钮十次,如第三图。

    JProbe

         我们使用JProbe 记录该过程中内存中对象的变化情况,如下图:

    JProbe

         我们现在将寻找堆中的游离对象-即"内存泄露"对象。基于前面的假设,你希望Jbutton类的变化数量应该为0即堆中应该没有Jbutton实例了,因为在上面的试验中我们最后移走了所有创建的按钮。实际上,Jbutton对象没有被移走并且可能继续游离在堆中。

         1. 首先在Instance Summary中查看每个类的Count Change,如果该数据不为0则表示用例运行完后,JVM堆中该类的实例数发生了变化。因为我们要识别游离对象,就要查看用例运行完后,JVM堆中的实例数是否发生了变化,也就是在执行时引用的对象到最后是否被释放。如果用例运行完后,堆中的实例数发生了变化,则说明可能存在游离对象。如果Count Change列没有显示出来,右击Class List,选择Show/Hide Columns,选中Count Change点击OK。

         2. 在Filter Classes域中输入*.Jbutton可以快速定位出Jbutton类,因为在上面的试验中我们主要创建了Jbutton对象,所以我们在这里主要观察Jbutton类。

         3. 我们注意到Jbutton类的Count Change列显示为+10,这表示从开始运行用例到结束用例运行这段时间内,堆中增加了10个Jbutton对象。尽管我们主观认为在试验最后已经销毁了这十个对象,但实际上它极有可能还存在于堆中。

         到这里我们已经识别出堆中很有可能存在游离的对象,下一步我们将进一步定位到类和代码行。

         这部分我们将找到究竟是哪些存活对象还持有Jbutton游离实例的引用。打开Class View窗口查看snapshot中的数据,通过Instance Detail View可以更深入地看到Jbutton的细节信息,最后打开Source窗口我们将看到原来是Jbutton[ ]数组仍然持有游离对象Jbutton。

         1. 选中要分析的snapshot,点击Class View。打开的窗口显示了堆中的类。

         2. 选中Jbutton类并点击Instance Detail View。这样可以查看到该类更详细的信息,包括该类的实例化信息,一共实例化了多少个对象,每个对象都是由谁创建的,对象的调用树和被调用树等。

         3. 点击工具条上面的View Only Instance Allocated After Checkpoint。这将移走那些在前面设置断点后内存中分配的对象,因为我们主要关心的是用例是否存在游离对象,所以不必查看运行用例前内存中的信息,现在你应该只看到十个实例。

    JProbe

         4. 选中任意一个Jbutton实例并点击Memory Leak Doctor,打开Memory Leak Doctor窗口。里面分别用不同颜色表示了对象的创建是在记录过程前和记录过程中等两种情况。游离对象通常在用例运行时即开始记录后增加的,但可能跟记录前创建的对象有点联系。对于这些游离对象,只有一个可能原因。以前存在的LeakExample实例引用Jbutton[ ]了,而Jbutton[ ]则引用了Jbutton实例。

    JProbe

         5. 我们模拟在程序中释放某个引用后,看该引用所关联的对象是否就可以被垃圾回收,如果可以垃圾回收说明可能存在游离对象。在这里我们看到Jbutton[ ]还持有Jbutton的引用,我们假定Jbutton是游离对象,选中Jbutton[ ]和Jbutton之间的引用,右键点击并且选择Remove Reference。这时系统将提示如果你在用例的程序中释放了这个引用,这个实例将被垃圾回收。这只是唯一一个引起游离对象的可能原因。

         6. 关闭Memory Leak Doctor窗口。接下来查看分配该实例的方法,并深入该分配方法的代码,查看该方法最后是否释放了该实例。

         7. 在Instance Detail窗口中,选中Jbutton实例,看Allocated At区域。我们将看到该实例是由方法LeakExample.addButtonToPanel( )分配的。

         8. 查看该分配方法的源代码,右键点击LeakExample.addButtonToPanel行并选中Allocated At Source。

         9. 找到用例的源代码,弹出的窗口显示选中的addButtonToPanel( )方法并定位到了分配Jbutton实例的代码行。至此,你看到了按钮是在什么地方被添加到buttons[ ]数组的了。

    JProbe

         10. 在Source窗口中找到removeButtonFromPanel( )方法。我们将注意到执行从button[ ]数组移走按钮的代码行嵌在if语句中,实际上,这个条件永远不能满足,它自始至终没有被执行到。这就造成了Jbutton实例一直存在于内存当中,变成了游离对象。(稍后我们可以修改其if的条件或满足该条件,让用例可以执行到里面移走Jbutton实例的代码,这时将看到内存明显得到改进并且内存中不再存在Jbutton实例)

         11. 到这里,我们已经证实button[ ]数组从用例开始运行到结束一直持用Jbutton实例的引用,我们可以肯定内存中存在游离对象。

         在运行改进后的用例前,你也可以使用JProbe计算这些游离对象一共消耗多少内存。选中Jbutton实例并从Tree Type下拉列中选择Reference Tree,这时你将发现Jbutton实例在内存中还引用了很多其它实例。点击Calculate就可以计算出这些游离对象消耗的内存大小了。


    (北京铸锐数码科技有限公司 www.InnovateDigital.com)

     
    北京铸锐数码科技有限公司 版权所有 © 2009
    中国·北京市丰台区方庄芳群园四区21号楼南方证券大厦422/424室
    邮编 100078 电话 010-62139280 传真 010-62135268    京ICP备05019494