【转贴】JAVA代码检查与内存泄漏分析

上一篇 / 下一篇  2007-11-21 23:48:48 / 个人分类:java相关

       对于Java代码,首先要求是它必须正确,能够按照程序员的真实设计思想运行,在保证程序运行正确的基础上进一步要求代码必须清晰易懂,除编写者之外其他程序员能够容易理解代码的含义。在软件工程领域,程序的统一风格标志着程序的可读性、可维护性,是软件产品的一个重要组成部分。在缺乏统一编码规范的情况下,很多时候,容易造成同一开发小组之内的多个程序员编写的程序风格各异,程序可读性、可维护差。通过建立代码编写规范,形成开发小组内乃至组织级编码约定,提高程序的可读性、可维护性,可以保证程序代码的质量,继承软件开发成果,充分利用资源,使开发人员之间的工作成果可以共享,利于编码过程的高效推进,降低项目开发过程中人员变更后代码难于维护所带来的风险。

1 代码评审
        目前多数Java集成开发环境都自带源代码格式化、美化功能,如Eclipse、JBuilder等。DevPartner系列下的OptimalAdvisor从项目管理、测试角度出发,提供对代码进行规范性检查。以下简单介绍OptimalAdvisor V4.00的使用。
        打开OptimalAdvisor,在待检查代码上建立代码模型(code model),如图1,可以选择SourceCode或者ByteCode模式进行源码扫描,SourcePath项指定一个或多个源码存放路径,ClassPath指定一个或多个类路径,可以选择是否支持jdk1.5。


图1 建立代码模型


        点击build按钮开始执行代码扫描,OptimalAdvisor会在指定的源文件目录下对所有java源文件进行扫描,默认使用所有内置的规则,在扫描完成后会显示当前代码的包结构(如图2)以及所有的与预置规则不符合的语句(如图3),也可以都代码扫描时使用的规则进行定制(如图4),点击SelectRules按钮,在弹出的规则列表页选择的特定规则对代码进行扫描。同时OptimalAdvisor还支持在原有规则基础上修改形成新规则,在。在违反规则的详细列表中,可以准确定位到违反规则的语句(如图5),代码检查结果能以html或xml文件方式轻松导出。


图2 包结构

图3 违反规则项统计

图4 选择规则

图5 定位语句


2 内存分析
        在解决了源文件规范问题后,很多的Java程序在长时间运行后都会出现内存使用量成倍变大,甚至导致机器最终内存耗尽而不得不重启,从现象上可以初步判断是程序运行过程中发生了内存泄漏,众所周知C、C++程序员在对内存空间进行分配操作后,如果忘记对已分配的内存空间进行释放就会引发内存泄漏,Java是通过垃圾收集器(Garbage Collection,GC)自动管理内存的回收,程序员不需要通过调用函数来释放内存,因此容易产生这样一个误解:Java编写的程序不会产生内存泄漏,导致程序员在编写代码时放松了对程序逻辑的深入理解,导致程序运行后随时间出现内存占用量水涨船高的现象。GC可以自动管理内存的回收,但它只能回收无用并且不再被其它对象引用的那些对象所占用的空间。在下面的代码中,循环申请Object对象,并将所申请的对象放入一个Vector中,如果仅仅释放对象本身,但是因为Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。
Vector v = new Vector(10);
for (int i = 1; i < 100; i++)
{
Object o = new Object();
v.add(o);
o = null;
}//此时,所有的Object对象都没有被释放,因为变量v引用这些对象。
        实际上无用,而还被引用的对象,GC就无能为力了(事实上GC认为它还有用),这一点是导致内存泄漏最重要的原因。
        Java采用了垃圾回收机制,任何不可达对象都可以由垃圾收集线程回收。因此通常说的Java内存泄漏其实是指无意识的、非故意的对象引用,或者无意识的对象保持。无意识的对象引用是指代码的开发人员本来已经对对象使用完毕,却因为编码的错误而意外地保存了对该对象的引用(这个引用的存在并不是编码人员的主观意愿),从而使得该对象一直无法被垃圾回收器回收掉,这种本来以为可以释放掉的却最终未能被释放的空间可以认为是被“泄漏”了。
使用DevPartner Java Edition可以轻松实现对象内存分配跟踪,泄漏检查,并且能定位到相关源文件中产生内存泄漏的语句。DevPartner Java Edition可以支持对应用服务器或本机上运行的程序进行内存泄漏检查。以DevPartner Java Edition的安装目录下的samples文件夹下的stackLeakExample项目为例,按以下步骤进行内存泄漏检。
在命令行下执行:
nmjava –mem stackLeakExample.StackLeakMain
系统显示DevPartner Java Edition的session control页,如图6:



图6 内存分析类型选择


        选择“Memory Leaks”,点击下方的“Start Tracking”,开始对系统当前点记录点以后系统产生对象的内存分配情况的跟踪,转到命令窗口下,输入“40”,即对stackLeakExample项目中定义的次Stack对象进行40次push,pop操作,此时可以从session control页上看到有40个新生成的StackEntry对象,如图7中红色框中标识出来的数据:



图7 内存分配跟踪


        点击session control页的“Run Garbage Collection”按钮进行垃圾回收,如果程序中对stack的push和pop操作编写正确,在gc进行垃圾回收后,StackEntry对象将被回收,点击session control页上的“View Memory Leaks”按钮,查看程序的内存泄漏情况。如图8:


图8 查看内存泄漏情况

        从图中可以看到,StackEntry发生了内存泄漏,点击该类可查看发生内存泄漏的对象列表,如图9:


图9 发生内存泄漏对象列表

        选择任意一对象,可以查看该对象的内存分配、所引用用的其它对象,同时能够定位源文件中发生内存泄漏的 语句,如图10:


图10 定位语句

        查看源文件中Stack的push、pop操作,可以发现是pop操作中的如下语句:
public Object pop()
{
Object e = elements[--size];
return e;
}

        正是pop操作中只返回了e,而没有将elements中无用的对象赋值为null,如果将该段程序进行如下修改,则StackEntry不会发生内存泄露。

public Object pop()
{
Object e = elements[--size];
elements[size] = null;
return e;
}

3 小结
        Java代码规范性检查和内存使用情况跟踪是对源码质量检查的常规性操作,在代码书写过程中通过有计划的对代码进行这两类检查能帮助程序员逐渐形成良好的编程习惯,并对最终代码的质量提供有力保障,在测试过程中加入这两类活动能从代码级给出评估意见,对被测试者也有更强的说服力,与其它黑盒测试方法相结合,能较全面的将软件的表现跟底层代码进行关联,增强测试最终回报。


TAG: java相关

水印 引用 删除 puchonghui   /   2007-11-23 11:57:09
图片我换成本地的了
再看不到我就没办法了。。。- -
FLY 引用 删除 j3smcgm1231   /   2007-11-23 10:03:24
为什么我看不到图哇。。。想看。。
四处游荡的风! 引用 删除 pose_123   /   2007-11-22 11:33:03
谢谢~!!
 

评分:0

我来说两句

Open Toolbar