http://blog.sina.com.cn/xuanzhicheng[订阅]
个人资料
评论
读取中...
图片幻灯
友情链接
访客
读取中...
好友
读取中...
博文
 

一. 软件规模度量的必要性

软件项目规模的度量,是软件项目中相当重要的一环.

只有相对合理和相对准确地度量软件规模,才能对项目的计划进度安排,资源分配,等等各个环节进行合理的部署.这样才能尽可能地保证软件项目的进度和质量.

原因是:

1.            软件项目与其它项目,例如建筑工程项目,汽车制造项目等,都有可以通过加大资源投入而获得更大生产力的特点.比如增加一条汽车生产线,生产能力能马上提高一倍.(当然其中仍包括一些工业生产线上的一些如何最大化流水线的技巧理论问题,但从总体上来说,软件生产不具备这样的特点),当加大软件开发资源的时候,如果管理不善,会出现生产力下降的情况.尽管其它的工业生产也可能发生这样的情况,但软件生产发生的概率要大很多.

2.            有90%的软件项目难以预测,只有10%的软件项目能在够在预定的费用和进度下交付.从这个角度看,能否准确地度量软件的规模,成为软件项目成功的重要矛盾点.

3.            软件项目规模的相对准确度量,能为项目计划,为项目的甲乙双方的资源分配调动提供有力的招引,尽管软件项目的度量是不可能完全精确的.有目的性地进行度量,能让项目组对软件开发的整个过程中出现的各种问题和风险有预先的估计,避免盲目从而能在实际上有效的提高软件项目的生产水平.

二.软件项目规模度量的相关方法及其局限

  比较流行的软件规模度量的方法是代码行(LOC)和功能点(FP)两种

        代码行度量的方法

代码行度量的方法,是通过各种手段,统计出软件项目的代码行.从而按代码行的数量为单位度量出软件的规模.

一般使用代码行度量自动化工具来进行度量,要度量的文件类型包括软件项目中交付用户使用的各种文件. 一般来说,如果项目的配置管理是使用CVS的话,可以使用StatCVS进行代码行度量.

LOC方法的优点是:

1.       度量工作容易进行,而且自动化度量工具非常多,即使自行开发难度也不高

2.       代码行数是比较公认的软件规模的标准,容易在项目的甲乙双方中取得共识.

规模度量的方法缺点是非常明显的.

1.              很难在项目分析论证和计划阶段就对软件的规模进行相对准确的度量. 即使进行度量

2.              即使进行度量,也必须依靠于评估人员的经验所得.虽然只要评估人员经验足够,可以获得比较准确的度量结果,但是这对评估人员的能力要求比较强,并而且难以由第三方对评估人员的工作偏差作出修正.

3.              不同软件项目使用的技术不一样,这一点,非常影响到软件规模的度量.例如同一个功能,使用JAVA语言和使用Ruby语言所涉及的代码行相差数十行,甚至数百行. 即使同为JAVA语言,使用不用的框架所需要编写的代码行也不一样.

 总体来说,LOC方法很适合软件业初期,使用比较简单的程序开发语言的项目进行规模度量,但是随着软件工业的发展,LOC方法进行度量的难度越来越大,而准确和可操性在逐渐降低.L

        功能点(FP)度量的方法

功能点法是一种面向功能的软件度量方法。一般来说,功能点法的计算根据软件需求规格说明书进行计算,在计算过程中需要充分利用DFD、E-R或UseOase图等提供的信息。

 

面向功能的软件度量是对软件和软件开发过程的间接度量。面向功能度量的关注点在于程序的“功能性”和“实用性”,而不是对LOC计数。一种典型的生产率度量法叫做功能点度量,该方法利用软件信息域中的一些计数度量和软件复杂性估计的经验关系式而导出功能点FPs(Function Points)。

功能点通过。首先确定五个信息域的特征,并在表格中相应位置给出计数。信息域的值以如下方式定义:

用户输入数:各个用户输入是面向不同应用的输入数据,对它们都要进行计数。输入数据应有别于查询数据,它们应分别计数。

 用户输出数:各个用户输出是为用户提供的面向应用的输出信息,它们均应计数。这里的输出是指报告,屏幕信息,错误信息等,在报告中的各数据项不应再分别计数。

用户查询数:查询是一种联机输入,它导致软件以联机输出的方式生成某种即时的响应。每一个不同的查询都要计数。

 文件数:每一个逻辑主文件都应计数。这里的逻辑主文件,是指逻辑上的一组数据,它们可以是一个大的数据库的一部分,也可以是一个单独的文件.

 外部接口数:对所有被用来将信息传送到另一个系统中的机器可读写的接口(即磁带或磁盘上的数据文件)均应计数。

通过对上面几个重要信息域的收集,可能定义出软件项目的功能点的数量,再使用如下的关系式:

 

               FP = 总计数×〔0.65+0.01×SUM(Fi)〕             

 

(其中,总计数是由表2所得到的所有加权计数项的和;Fi(i = 1到14)是复杂性校正值,它们应通过逐一回答表2所提问题来确定。SUM(Fi)是求和函数。上述等式中的常数和应用于信息域计数的加权因数可经验地确定。Fi是对影响产品规模的14个因素进行分析确定的“复杂度调整值”,取值范围是0-5)

就可以计算出FP的数量

 

FP方法的优点

放弃了依赖于技术细节的LOC方法简单线性标准,通过功能点来进行估计,这样一来甲方对发包产品的成本估算、乙方对自身开发成本的预测提供了便利, 比如,A软件项目的规模是100功能点,我们根据行业基准(Benchmarking)知道平均成本是5000元/功能点,那么本项目的成本预测就是50万元;我们又根据行业基准知道平均生产率为1功能点/人天,则计算得到项目需要投入100个人天的工作量,这些计算的结果将成为签定合同的依据和软件项目管理的基础

 

其缺点,仍然是没有考虑到不同的开发项目团队和开发条件下的不同状况,只是从一些平均普遍的方法上去进行度量,因为和实际项目的差距,造成了这种方法的缺陷.

 

三.软件规模度量的目标的再次明确

   软件规模度量的目标,是为了在项目初期能对软件项目的整个过程进行估计,预先制定好比较合理的软件项目管理计划,制定合理的软件项目的风险处理机制,最终保证软件项目的顺利完成.

脱离了这个目标,笔者认为,再好的软件度量方法也是没有意义的.因为软件开发的过程,受到影响的因素太多,包括开发人员的熟练程序,水平,配置管理环境的完善与否,所使用的技术和设计方案合理与否,测试机制合理与否,都有关系.

而这些因素,每个软件项目开发的团队都是不一样的,这些因素本身就难以度量.

传统的功能点和代码行的度量方法.在实际的开发中,往往脱离了对实际项目环境,因此盲目的使用传统的度量方法进行度量工作,往往是白费的.

 

四.软件项目度量在实际项目中的认识.

        软件项目度量是软件开发团队的能力和素质,是需要长期培养的生产力.

不同的开发团队,由于其开发软件项目所熟练和精通使用的技术不同,因为软件项目的度量,必须要以这些团队自身特长的技术作为基础,如果使用通用的度量方法,是必然会引起偏差的.

        不同软件项目的度量,必须要以开发团队的开发历史数据为基础.才能获得更准确的估计结果. 由于每个开发团队使用的技术,开发环境,配置管理环境,等等这些因素,是会极大的影响软件开发的进度的.例如,配置管理,部署发布的自动化程度. 因此

        软件开发团队的人员稳定,并且改善开发技术,保存项目度量的历史数据,对软件规模的度量有着重要的作用.

 

五.软件项目度量在实际项目中的手段 :

1.建立软件规模度量的历史数据库(面向团队).这个数据库必须由团队每一个成员共同维护,每个项目的分任务完成后,要将完成的时间,所使用的资源记录在数据库中.特别是要记录任务的使用条件.例如,完成任务一使用的是Hiberante技术,而完成任务二使用的是ibatis技术等.完成任务三使用的是loadrunner工具(测试),完成任务四是使用jmeter工具等.

  有了这些数据,就能比较清晰的知道,使用不同工具完成任务的大致时间.

2.在项目计划中,进行任务分解的时候,一定要注意任务的粒度不能太大,一般要求在三天到一周之内.如果任务粒度太大,会增加规模度量的误差.同一个任务,当开发人没的熟练程度改变时, 就能引入误差,而粒度越大,引入的误差也会越大.

同样地. 记录于历史数据库中的任务粒度,也要保持三天到一周的标准

3.软件规模的度量要集合全体团队成员一起进行.团队成员中每人有自己的特长,要因应其特长进行估算,才能获得最大效果.

4.度量的时候,一定要将所有的度量单位,转化为时间人力成本和固定投资成本两种单位,只有这样,才能使软件规模的度量,贴合到甲乙方的生产资源利用的实际情况,才能保证项目的顺利完成.

5.必须要将软件生产中,硬生产内容和软生产内容所占用的时间都计算在度量范围内

硬生产内容,是指软件项目的设计,编码,调试,测试等内容,这些内容生产出来的成品,是可以交付给甲方的.属于最终产品的一部分.

软件生产内容,是指软件开发过程中,乙方硬件配备,开发环境的搭建,配置管理环境的搭建等,开发必不可少,但又不会有成品产生交付给甲方的工作内容.但这些内容,也实际占用了软件开发的时间,因此是必须将其纳入度量范围,才能更准确度量出软件项目的规模.

6.必须每周都要根据项目的实际情况,进行新的度量,如果度量的结果和预计有偏差,应该向要让甲乙双方所有项目参与人员通报,并制定相应的方案.

7.由于缺陷(Bugs)的清除,通常会占项目开发时间30%以上,因此缺陷(Bugs)的度量在整个项目的规模度量中,是占最重要的位置的.许多项目的度量忽视了对缺陷量和程度度量,往往会造成了项目时间和成本度量的巨大偏差.

 

六.总结

   软件规模的度量,能够项目的成本预算估计,可行性分析,项目计划提供坚实的工作基础.建议不同的软件项目,都根据实际的情况,进行尽量准确的规模度量.

   规模的度量,一定要将度量的结果,转化为时间人力成本和资源资金成本,才能为项目提供最直接的预测支持.

   软件规模度量结果需要在项目过程中不断修正的.

   软件规模度量,是软件开发团队要持续改善的能力.

参考资料: 软件产品的规模度量-功能点与代码行 [肖鹏]

《功能点分析方法与实践》李帜等编著 清华大学出版社 2005

功能点法在软件项目早期规模估算中的运用 [陈兵]

 

二.    Action -> JSP

当要从Action中执行的loadCity方法,要返回到jsp页面时,要在页面上指定一个return的页面.我们在admin-action.xml配置中可以看到一句

<result name='city'>/admin/city.jsp</result>

而在loadCity方法中有这样一句

return 'city';

这样,当loadCity执行完后,就会返回到http://localhost/admin/city.jsp页面.

由于在action中,cityId和mthCity.cityId是被前一个提交过来的jsp页面赋值过,所以当程序执行转到city.jsp页面的时候,这几个值是能被使用的.我们使用jstl来获得这些值

 ${cityId} , ${mthCity.citId} (前提是只要在action中,设定了cityId和mthCity类的getter/setter.)

 

 

1.       当action中的类,传到受hibernate管理的命名空间的类中时

这个问题比较特殊.

我的工程中,建立了一个类cityService.这个类是进行数据库操作的,也就是和hibernate打交道的.而这个类在hibernate的设置中设置为被一个hibernate Session管理的范围.

这个cityService中有一个方法,用于更新city的信息的

    public void updateCity(MthCity city) throws DataAccessException,

    BaseException{

 

        MthCity icity = this.getCityById( city.getCityId());

        icity.setCityName(city.getCityName());

baseHibernateDAO.update(icity);//这个baseHibernateDAO只是一个封封装了hibernate  API的包,网上常见.

 

    }

大家可以看到,方法中并没有直接update从参数传进来的city,而是新建了一个icity,装了city中的信息再进行update.

 

这是因为,cityService这个类被hibernate管理,所以在这个类中创建的内容,才能被更新.所以我们必须使用一个新的MthCity类实例来装着外面传进来的内容,才能更新.否则就会出现类似have the same id object in the session的错误,也就是说session中有其它相同id的对象的错.

 

当然,有另一个处理办法,就是使用baseHibernateDAO.merge来更新内容,而还是用update

这里就可以写成

public void updateCity(MthCity city) throws DataAccessException,

    BaseException{

 

baseHibernateDAO.merge(icity);

}

 

 

2.    Hibernate中的version类型成员

在我的项目中,city有一个属性是timestamp,对应的是mth_city这个表,这个表通过hibernate的映射,映射成一个POJO对象

public class MthCity implements java.io.Serializable {

    private Long cityId

    private Date timestamp;

   

    private String cityName;

    public MthCity() {

    }

 

    public Long getCityId() {

       return this.cityId;

    }

    public void setCityId(Long cityId) {

       this.cityId = cityId;

    }

 

    public Date getTimestamp() {

       return this.timestamp;

    }

    public void setTimestamp(Date timestamp) {

       this.timestamp = timestamp;

    }

    public String getCityName() {

       return this.cityName;

    }

    public void setCityName(String cityName) {

           this.cityName = cityName;

    }

}

 

大家可以看到,类中有一个属性是timestamp,定义为Date类型.

这个类型是用于记录数据库操作的日期的,数据库中的对应字段也叫timestamp.看一下hibernate的映射配置

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-mapping PUBLIC '-//Hibernate/Hibernate Mapping DTD 3.0//EN'

'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>

<!--

    Mapping file autogenerated by MyEclipse Persistence Tools

-->

<hibernate-mapping>

    <class name='com.mytophome.admin.domain.MthCity' table='MTH_CITY' dynamic-update='true'>

        <id name='cityId' type='java.lang.Long'>

            <column name='CITY_ID' precision='10' scale='0' />

            <generator class='sequence' />

        </id>

        <version name='timestamp' type='java.util.Date'>

            <column name='TIMESTAMP' length='7' />

        </version>

        <property name='cityName' type='java.lang.String'>

            <column name='CITY_NAME' length='80' />

        </property>

    </class>

</hibernate-mapping>

 

大家可以看到,cityid对应数据库表中的CITY_ID字段,其值由oracle sequence生成

而timestamp属性,对应的是数据库的TIMESTAMP字段,并且这个属性在mapping中定义为<version>属性

这样,就会出现两点要注意的地方

        数据库中的这个timestamp的字段一定要有值,并且是日期值,否则当hibernate更新这个字段没有值的那条记录时,会出现如下错误

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.mytophome.admin.domain.MthCity#1]

        在更新MthCity中的值到数据库中,也就是更新一条记录时,一定不设调用方法人工设置timestamp属性的值,也就是下面的语句不能出现

mthCity.setTimeStamp(new Date());

否则也会引起hibernate的出错.

 

由于开发任务紧张,因为这里的开发笔记,仅用于记录遇到的几个struts2和hibernate结合开发的现象.不对其做分析.

1.       在使用struts2时,页面和action之间的传值

这是struts2和struts1最大的区别.

Struts2中,action和jsp页面之间的信息交互,是通过 action中定义的成员变量来实现的.

例如,我在一个名为EstateAction的类中有如下定义

public class CityAction extends BaseAction {

    private MthCity mthCity ;

    private String cityName;

    private Long cityId

    private int couter;

 

    public String loadCity() throws DataAccessException, BaseException{

        counter ++;

        return 'city';

    }

}

然后,这里上面的类中的成员类MthCity的定义如下

public class MthCity implements java.io.Serializable {

   

    private Long cityId 

    private String cityName;

    public MthCity() {

    public Long getCityId() {

       return this.cityId;

    }

    public void setCityId(Long cityId) {

       this.cityId = cityId;

    public String getCityName() {

       return this.cityName;

    }

    public void setCityName(String cityName) {

           this.cityName = cityName;

    }

}

这是一个Hibatenate使用的数据对象 POJO类.

有了这两个类后,我们来看看Struts2的Action和JSP页面之间是如何交互的

一.    JSP -> Action

Jsp页面

        以下是一个jsp页面submit.jsp.这个页面只有一个功能,就是向struts提交申请

<%@ page language='java' contentType='text/html; charset=gbk'%>

<%@ include file='/common/taglibs.jsp'%>

 

 

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>

<html xmlns='http://www.w3.org/1999/xhtml'>

<head>

<meta http-equiv='Content-Type' content='text/html; charset=gbk' />

<title>提交</title>

</head>

<script>

    function go (){

      window.location ='${pageContext.request.contextPath}/admin/city/loadCity.do”;

  }

</script>

<body>

<form name=”myform” >

  <input type='button' name='cityupdate' id='cityupdate' value='编辑' onclick='javascript:go();'/>

  <input type='hidden' name='mthCity.cityName' id=' mthCity ' value='广州' />

 

</form>

</body>

</html>

 

大家可以看到,这个页面只有一个按钮,将页面提交到struts的一个action中,这是为什么呢.

        我们先看一段struts2的配置文件admin-action.xml

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE struts PUBLIC

    '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'

    'http://struts.apache.org/dtds/struts-2.0.dtd'>

<struts>

    <package name='admin' namespace='/admin' extends='struts-default'>

       <action name='city/*' method='{1}'

       class='com.mytophome.admin.representation.struts.action.CityAction'>

       <result name='city'>/admin/city.jsp</result>

       <result name='city_update'>/admin/city_update.jsp</result>

       </action>

    </package>

</struts>

 

这是一个struts2的典型配置文件.

上面有几处要注意的

首先是namespace = “/admin” 这是一个struts模块名,可以不写,但如果写了,能比较方便的将struts2的action按配置来分模块.(何谓分模块呢?struts2有个特性,是action定义不需要像struts1一样写在同一个struts.xml文件中.而是可以使用include的形式.例如我使用的项目的struts.xml文件就是这样写的:

<struts>

    <include file='struts-action/admin-action.xml'/>

    <include file='struts-action/agent-action.xml'/>

</struts>

这样include了一系统的xml配置,而上面的admin-action.xml文件就是其中一段,因此将这一段中涉及的action类设定为一个模块,就定namespace = “/admin”

)

其次

<action name='city/*' method='{1}'

这一句配置的意思,就是,当用户提交一个符合struts2格式的申请时(所有包含.do形式的http链接)

例如http://localhost/admin/city/loadCity.do

这一条是特定的struts2请求链接.

所以struts会通过配置解析,这里要特别提一下的是,这链接中的admin,就是struts定义中的namespace='/admin'中的admin. 要访问这个action的方法,就一定要按namespace 中定义的名称来访问.

其中包含了/city/那么在配置 文件中,只要定义action name=”city/*”,那么所有包含有/city/的do,都会提交到action定义的类中来,也就是类om.mytophome.admin.representation.struts.action.CityAction中,那么提交到这个类的哪个方法中呢? 因为选择的是city/*.而且mothed={1},所以方法名由链接指定

也就是loadCity.do所指定的.loadCity方法.

 

        这个do方法后面是可以带参数的.所带的参数名,要是CityAction中定义的成员变量,包括成员类.例如,如果想提交后,CityAction中的cityId有值,链接可以这样写

http://localhost/admin/city/loadCity.do?cityId=9

这样,在loadCity方法中,如果你访问cityId,就可以发现cityId的值是9

System.out.println(Long.toString(cityId));

 

但这里有一个条件,就是CityAction中,必须要有cityId变量的getter/setter方法(这两个方法可以用MyEclipse自动生成)

    public Long getCityId() {

       return cityId;

    }

 

    public void setCityId(Long cityId) {

       this.cityId = cityId;

    }如果要给CityAction中的MthCity类的

这样才能在jsp页面提交时,由struts为cityId赋值.(当然,getter方法就方便当action返回到jsp页面时,cityId的值能在页面取到.)

        如果要为action中的类成员变量赋值也是可以的

例如http://localhost/admin/city/loadCity.do?cityId=9&mthCity.cityId=8

这条链接提交后,会和上面一样调用CityAction的loadCity方法,但这里,action的成员mthCity会被创建实例,并为mthCity的一个属性cityId赋值,也就是说,在action中,大家可以通过mthCity.getCityId()来获得这个属性的值.

当然,一定要在action设置mthCity的getter setter,jsp上的内容才能传到action中

    public MthCity getMthCity()

              return mthCity;

    }

 

    public void setMthCity(MthCity city) {

       this. mthCity = city;

    }

 

 

        从JSP提交内容到Action,还有一种方法,就是将参数内容放在表单form的元素中

  <input type='hidden' name='mthCity.cityName' id=' mthCity ' value='广州' />

 

这样,当用以下语句表单提交的时候

doucment. myform.submit();

就能在Action中创建一个mthCity实例,并为mthCity.cityName设置值为:广州.

原因是在页面的表单元素中,设置了name= mthCity.cityName,而action中刚好有成员类叫mthCity,而这个类中刚好有属性叫cityName.,就是通过这样的方法,能将表单的内容,提交到Action中.

关于敏捷开发的总结(2007-08-24 18:06)
   对于软件的敏捷开发.世上有许多理论.包括xp之类的方式.作为一个软件设计师,我对这些理论听得很多,但实际的工作中,却有许多和理论预想中不一样的情况.
 
  在这里,我首先设定三条规则,来作为jnt团队开发管理的准则.至于这个准则的解释(为什么要用这三条准则),将会在后续的文章中说明
 
1.每个任务周期不能超过五天
2.每个任务必需要包括一个关键点和一个次要点
3.每个任务要有实物出现
 
这里,有几个名词要重点注意,就是关键点,次要点和实物.
什么是关键点,什么是次要点,何谓实物.这里要解释一下.
这几个名词的解释,一定要从使用者的角度去说,因为软件是让客户使用的,如果不从客户的角度考虑,那么软件就是失败的。
 
那么,关键点就是能让使用者减轻工作负担,加快效率的功能。也就是说,能让使用者满意的功能,但是非常必要的,没有了这个功能,那么这个模块就等于不能使用的
次要点,就是能让使用者满意上再加满意的功能。但并不是最主要的,即使没有,都不会影响使用。
实物,就是能让使用者使用的,具有现实功能的模块(不需要是整个软件),大家可以看成是软件的一个版本,并为每个版本定一个版本号。 不停的演化,最后演化出整个软件。
 
 
 

 

我们在一般的apache + tomcat的组合下配置虚拟主机的文章很多,但当我需要在Windows2000,要配置IHS (IBM Http Server) + Websphere 的虚拟主机时,却发现资料严重不足,而配置过程也并非我想像中容易.因为HIS的配置是要由Websphere的配置去影响和传播的.特写文章记录.

1. httpd.conf

NameVirtualHost 61.145.126.83 注释掉

# Win32DisableAcceptEx 注释去掉对性能有帮助

 

2.对管理控制台:

环境 ->虚拟主机-default_host -> 将主机别名里的 * 80 *443 去掉

proxy_host,如果没有人用就删除,如果有人用,要将 *:80, *:443 改为特定的名字 :80 ip:80,不能用 *

 

3. 然后创建4个新的虚拟主机,名字例如为

dg_host 然后主机别名为 dg.mysite.com 和端口 80, 以及 dg.mysite.com 和端口 443

gz_host 然后主机别名为 gz.mysite.com 和端口 80, 以及 gz.mysite.com 和端口 443

sz_host 然后主机别名为 sz.mysite.com 和端口 80, 以及 sz.mysite.com 和端口 443

zh_host 然后主机别名为 zh.mysite.com 和端口 80, 以及 zh.mysite.com 和端口 443

保存配置, 停止服务器

 

4. :<%WebSphereHome%>AppServer/profiles\AppSrv01/config\cells/applications/dgweb.ear/deployments/dgweb/dg.war/WEB-INF

ibm-web-bnd.xmi 里的 default_host 改为 dg_host

<%WebSphereHome%>/AppServer/profiles\AppSrv01/config\cells/applications/dgweb.ear/deployments/dgweb/META-INF/applications.xml 里的 <context-root>dg</context-root> 改为 <context-root>/</context-root>

 

对另外3个也一样,只是 default_host 分别为 gz_host, sz_host, zh_host

 

或者可以在管理控制台->企业应用程序->选择应用程序->将虚拟主机映射到web服务.

在里面改虚拟主机和应用程序的关系也可以

 

5.启动服务器,管理控制台-〉服务器-> webserver1->重新生成插件

重起 IHS

 

2007年6月27日壬辰(2007-06-27 22:07)
 从今天起开始在此记录各个项目的开发任务和每个任务的完成情况
 
1.安装PowerDesigner 12 配置好设计环境。 完成日期:2007-07-01
2.分析第一个用例。并创建好编码的环境和平台 完成日期:2007-07-05
3.通过用例,进行业务逻辑设计.  完成日期:
4.配置Spring 开发环境 完成日期:
 

 Windows下对WebSphere运行时内存溢出.CPU占用率高和自动停止的问题的监控

1.       出现内存溢出的时候.

在WebSphere运行的时候,如果出现了内存溢出,那么原因是多样的.可能是因为程序中有不良的代码,引致申请了的内存不能在使用后被释放. 可能因为程序结构不善,引致websphere容器花费大量开销用于优化造成.

这里有一点要特别注意,内存溢出的时候,通常的表现是Websphere的服务没有了响应,所以当服务没有响应的时候,我们可以假设其为内存溢出,然后按步骤做相应的信息收集.

无论哪种原因. 内存溢出的问题可以分成两类.

  NATIVE 这一类内存溢出,是整个Websphere进程在操作系统中的内存溢出,Websphere自身已经不能控制

    HEAP 这一类内存溢出是在容器管理下的程序运行出现了内存溢出.这一类的溢出能够在websphere的javacore中找到信息(下面我们会再次提到.)

 

先说一下,出现NATIVE类内存溢出的时候要如何处理.

    要对Websphere进行设置.开放详细垃圾收集选项.
步骤如下.(Webshpere版本 6.0.2.7)

在浏览器中输入http://服务器ip:9060/ibm/console 进入Websphere 管理控制台-> 登录->服务器->应用程序服务器->在服务器列表中选择需要调试的服务器->java和进程管理->进程定义->java虚拟机->将详细垃圾回收选项选上.

     使用userdump工具生成系统的内存境像,然后通过对境像的分析定位出现内存溢出的进程(userdump工具的下载路径: http://download.microsoft.com/download/win2000srv/Utility/3.0/NT45/EN-US/Oem3sr2.zip)
首先运行netstat -an > netstat_before.out 将收集数据时的网络状态记录下来.

打开Websphere的SystemOut.log文件,将文件最近的一次服务器启动记录找到.在这个记录中会找到现在正在运行并发生内存溢出的java进程的进程号.(如果最近一次启动服务器是失败的,那么在服务器对应的log目录中能找到一个server_name.pid文件记录中找到对应的进程号.)

然后在windows的命令行模式下,运行

userdump PID

这个PID就是先前的步骤中找到的websphere进程号

这样会生成一个叫java.dmp的文件. 将其改名成java1.dmp.

两分钟后再运行多一次userdump.生成的文件改名为java2.dmp.

两分钟后再运行多一次userdump.生成的文件改名为java3.dmp.

这样就能生成用于分析的系统内存映像文件.

 

(如果上面的步骤出现了问题,例如生成java.dmp的过程不能完成.还可以使用dr. watson强制生成userdump文件.方法如下:

在命令行中运行:

drwtsn32 -p pid

生成的userdump文件会放在

operating_system_root\Documents and Settings\
All Users\Application Data\Microsoft\Dr Watson

但这种做法的会同时停止java.exe进程.因此只有其它的生成userdump方法失效的情况下才合适使用.)

 

  使用wsadmin生成javacore,从javacore看出内存问题. (具体步骤请参阅2出现CPU占用率高的时候)
 

2.       出现CPU占用率高的时候

如果在WebShpere运行的过程中出现了高CPU占用率的引起的原因是多样的.但这里要分清楚瞬时高CPU占用率和占用率居高不下两种情况. 前者是正常的,因为有很多不同的程序在系统中运行,因为进程间的优先级,和CPU的能力所致,很多时候会出现一小段时间内CPU占用率的大幅提高.我们这里要描述的问题,是指CPU占用率高上去之后下不来的情况.

     先要在Windows系统中设置CPU占用率的监控.步骤如下.

在Windows的管理工具中选择 性能  打开性能监控器

点击工具栏上的”添加”增加监控内容,将右边方框中所有的java线程都进行选择.左边则选择Processor Time , ID Process ,ID Thead,如图

 

同样的操作,在计数器日志中要设置.

选择性能监控器中的计数器日志,点击右键->新建日志设置->输入名称->确定->添加计数器->然后仍是将所有的java线程选中,也选上Processor Time , ID Process ,ID Thead

如是图

 

这样做的目的,是让性能监控中内容,能在固定的log文件中记录下来.

       当cpu出现高占用率的时候,要在windows命令行方式中手动生成websphere的javacore,步骤如下.

 netstat -an > netstat_before.out

这个命令用于记录生成javacore时的网络状况.

 

在没有开启websphere soap安全方式情况下,使用

wsadmin.bat

打开websphere管理台.

如果在SOAP方式下,就要加入参数,命令行格式如下:

wsadmin.bat [-host host_name] [-port port_number] [-user userid[-password password]

在启动了wsadmin的状态后,运行以下命令设置好环境

wsadmin>set jvm [$AdminControl completeObjectName type=JVM,process=server1,*]

上面的server1就是要生成javacore的服务器的名称

 

环境设置好后,在wsadmin状态下运行

wsadmin>$AdminControl invoke $jvm dumpThreads

这样会生成一个javacore.

然后2分钟后再次运行

 

然后2分钟后再次运行

 

这样,就能在%Websphere%/AppServer/profiles/服务器名/ 这个目录下找到手动生成的三个javacore

        生成了javacore后,就通过性能监控器中,找到CPU占用率高的线程,然后我们可以看到下图

 

ID Thread中就是占用率高的线程号. 这个号是十进制的,将其转换成16进制的数字.例如图中的数字的十六进制形式是0xD98

这样我们能在刚才生成的javacore中找到这样的句子

'SoapConnectorThreadPool : 0' (TID:0x10A25A98, sys_thread_t:0x24A31B30, state:R, native ID:0xD98) prio=5

这个十六进制的进程号就是对应javacore中native id = 0xD98的内容,这样我们就能大致知道这个引起cpu占用率高的线程在做什么,然后进行排错调试.

 

 

3.       出现自动停止的问题的时候.

 当出现了更严重的情况,websphere的线程自动停止了.那以首先要需要两个方面的数据.

        程序中止时的自动NATIVE 的内存镜像.

这个工作需要借助Dr.Watson,

点击开始菜单->运行….->运行

drwtsn32

打开dr.Watson程序的窗口

 

对Dr.Watson的设置如图中所视,特别注意的内容是设置故障转储目录.当程序中止,我们在所设置的目录中找到需要的userdump文件.

设置好后

点击开始菜单->运行….->运行

drwtsn32 –i

这样,dr.Watson被设置为系统默认的调试器,会在程序中止时生成内存映像

至于Heap类型的内存映象,因为在Webshpere在中止时,会自动生成javacore文件,因为在程序中止后,直接到

%Websphere%/AppServer/profiles/服务器名/ 这个目录下找到自动生成的最新javacore就可以了

 

 

以上三个问题中所收集的数据,可以进行自己分析,对于javacore文件,分析工具是mddfj.IBM的网站上有相关文章介绍,在这里不再赘述.

也可以将这些文档发给IBM的客户服务中心,让他们的技术人员帮助分析.

 

 

希望这个文档,能帮助大家初步认识当Websphere出问题后,应该如何反应.欢迎批评指导…
 
 




  我已经在新浪BLOG安家了,欢迎你“常过来看看”,大家多多交流哦。我们可以一起把这里变成共同的心灵家园,像家一样温暖的地方。
  我会把一些新鲜有趣的东西记录下来一块与你分享,也希望你能够记住我的
BLOG地址,像老朋友一样经常过来做客——你可以把“她”添加到你的收藏夹中,也可以把“她”复制下来告诉你的朋友们。特别希望能通过你,让我认识更多的好朋友。如果还有不了解的,就跟着我一起来看看拥有所有博客知识和维护技巧的博客帮助站吧:http://blog.sina.com.cn/help/ :)

  我的BLOG地址:  http://blog.sina.com.cn/xuanzhicheng