ServiceMix环境配置

 

配置使用的ServiceMix版本是servicemix-3.3tomcat5.5以上运行(因为依赖包大部分是需要jdk1.5)

ServiceMix有三种部署方式:单独程序方式,servlet方式,Geronimo and JBoss.整合方式。这里主要介绍servlet方式,因为这样可以整合到任何servlet容器中。

Servlet部署需要在web.xml中配置spring加载文件,这种spring是和xbean整合的自定义配置文件。

 

配置文件说明:

Web.xml

 

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

<!DOCTYPE web-app

    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

    "http://java.sun.com/dtd/web-app_2_3.dtd">

 

<web-app>

  <display-name>ServiceMix Web Application</display-name>

  <description>Deploys ServiceMix inside a Web Application</description>

 

  <context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>/WEB-INF/jmx.xml /WEB-INF/core.xml /WEB-INF/activemq.xml</param-value>

  </context-param>

Spring配置文件

  <context-param>

    <param-name>contextClass</param-name>

    <param-value>org.apache.xbean.spring.context.XmlWebApplicationContext</param-value>

  </context-param>

 

  <listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

  </listener>

Spring 监听器

  <!-- servlet mappings -->

 

  <!-- the main JMX servlet -->

  <servlet>

    <servlet-name>JMXServlet</servlet-name>

    <servlet-class>org.apache.servicemix.web.jmx.JMXServlet</servlet-class>

    <load-on-startup>1</load-on-startup>

  </servlet>

 

  <!--  the HTTP binding servlet -->

 

  <!-- START SNIPPET: servicemix-http-->

  <servlet>

    <servlet-name>HttpManagedServlet</servlet-name>

    <servlet-class>

      org.apache.servicemix.http.HttpManagedServlet

    </servlet-class>

    <load-on-startup>1</load-on-startup>

  </servlet>

http bean组件(BC)servlet

  <servlet-mapping>

    <servlet-name>HttpManagedServlet</servlet-name>

    <url-pattern>/jbi/*</url-pattern>

  </servlet-mapping>

 

  <!-- END SNIPPET: httpBinding -->

 

  <servlet-mapping>

    <servlet-name>JMXServlet</servlet-name>

    <url-pattern>/jmx/*</url-pattern>

  </servlet-mapping>

 

</web-app>

 

demo主要功能的配置在core.xml:

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

<beans xmlns:sm="http://servicemix.apache.org/config/1.0"

       xmlns:http="http://servicemix.apache.org/http/1.0"

                   xmlns:my="http://servicemix.apache.org/demo/"

       xmlns:foo="http://servicemix.apache.org/demo/">

 

  <!-- the JBI container -->

  <sm:container id="jbi"

      rootDir="#rootDir"

      useMBeanServer="true"

                              createMBeanServer="false"

      MBeanServer="#jmxServer"

      installationDirPath="#installDir"

      deploymentDirPath="#deployDir"

                              monitorInstallationDirectory="true"

      transactionManager="#transactionManager"

      depends-on="broker">

 

    <sm:activationSpecs>

 

      <!--  an example HTTP binding for use by the SpringBindingServlet  -->

      <!-- START SNIPPET: http -->

      <sm:activationSpec componentName="servicemix-http" service="foo:httpBinding" destinationService="foo:echo">

        <sm:component>

          <http:component>

            <http:configuration managed="true" />

            <http:endpoints>

              <http:endpoint service="foo:httpBinding"

                             endpoint="endpoint"

                             targetService="foo:echo"

                             role="consumer"

                             locationURI="http://localhost/exampleUri/

配置url, 会被tomcat自动转换为serverapp/jbi/ exampleUri

"

                             defaultMep="http://www.w3.org/2004/08/wsdl/in-out

消息请求方式是in-out,即期望又返回消息

" />

            </http:endpoints>

          </http:component>

        </sm:component>

      </sm:activationSpec>

使用http BC,作为一个消费者(consumer)目标指向服务引擎(SE)foo:echo

      <!-- END SNIPPET: http -->

 

      <!--  a simple Echo service to test InOut message exchanges using HTTP-->

      <sm:activationSpec componentName="echo" service="foo:echo" >

        <sm:component>

          <bean class="org.apache.servicemix.components.HelloWorldComponent">

            <property name="property" value="name"/>

          </bean>

        </sm:component>

      </sm:activationSpec>

SE foo:echo,这是一个简单的helloworld

</beans>

 

经过这样的配置和在web.xml中配置的servlet,那么uri pattern形如 /jbi/exampleUri请求foo:httpBinding (BC),在ESB内部foo:httpBinding通过消息路由(normalized message router)foo:echo通信

Web测试页面链接为http://localhost:(tomcat端口)/ESB-ServerMix-Web/examples/

 

需要在firefox下测试。

测试页面使用ajax请求/jbi/exampleUri经过foo:httpBinding, foo:echo处理返回信息。

 

 

Continue reading ServiceMix环境配置

【转】几种常见的网络存储技术的比较研究

随着计算网络技术的飞速发展,各种网络服务器对存储的需求随之发展,但由于商业企业规模不同,对网络存储的需求也应有所不同,选择不当的网络存储技术,往往会使得企业在网络建设中盲目投资不需要的设备,或者造成企业的网络性能低下,影响企业信息化发展,因此商业企业如何选择和使用适当的专业存储方式是非常重要的。 
目前高端服务器所使用的专业存储方案有DAS、NAS、SAN、iscsl几种,通过这几种专业的存储方案使用RAID阵列提供的高效安全的存储空间。 
一、直接附加存储(DAS) 
直接附加存储是指将存储设备通过SCSI接口直接连接到一台服务器上使用。DAS购置成本低,配置简单,使用过程和使用本机硬盘并无太大差别,对于服务器的要求仅仅是一个外接的SCSI口,因此对于小型企业很有吸引力。但是DAS也存在诸多问题:(1)服务器本身容易成为系统瓶颈;(2)服务器发生故障,数据不可访问;(3)对于存在多个服务器的系统来说,设备分散,不便管理。同时多台服务器使用DAS时,存储空间不能在服务器之间动态分配,可能造成相当的资源浪费;(4)数据备份操作复杂。 
二、网络附加存储(NAS) 
NAS实际是一种带有瘦服务器的存储设备。这个瘦服务器实际是一台网络文件服务器。NAS设备直接连接到TCP/IP网络上,网络服务器通过TCP/IP网络存取管理数据。NAS作为一种瘦服务器系统,易于安装和部署,管理使用也很方便。同时由于可以允许客户机不通过服务器直接在NAS中存取数据,因此对服务器来说可以减少系统开销。NAS为异构平台使用统一存储系统提供了解决方案。由于NAS只需要在一个基本的磁盘阵列柜外增加一套瘦服务器系统,对硬件要求很低,软件成本也不高,甚至可以使用免费的LINUX解决方案,成本只比直接附加存储略高。NAS存在的主要问题是:(1)由于存储数据通过普通数据网络传输,因此易受网络上其它流量的影响。当网络上有其它大数据流量时会严重影响系统性能;(2)由于存储数据通过普通数据网络传输,因此容易产生数据泄漏等安全问题;(3)存储只能以文件方式访问,而不能像普通文件系统一样直接访问物理数据块,因此会在某些情况下严重影响系统效率,比如大型数据库就不能使用NAS。 
三、存储区域网(SAN) 
SAN实际是一种专门为存储建立的独立于TCP/IP网络之外的专用网络。目前一般的SAN提供2Gb/S到4Gb/S的传输数率,同时SAN网络独立于数据网络存在,因此存取速度很快,另外SAN一般采用高端的RAID阵列,使SAN的性能在几种专业存储方案中傲视群雄。SAN由于其基础是一个专用网络,因此扩展性很强,不管是在一个SAN系统中增加一定的存储空间还是增加几台使用存储空间的服务器都非常方便。通过SAN接口的磁带机,SAN系统可以方便高效的实现数据的集中备份。SAN作为一种新兴的存储方式,是未来存储技术的发展方向,但是,它也存在一些缺点:(1)价格昂贵。不论是SAN阵列柜还是SAN必须的光纤通道交换机价格都是十分昂贵的,就连服务器上使用的光通道卡的价格也是不容易被小型商业企业所接受的;(2)需要单独建立光纤网络,异地扩展比较困难;

四、iSCSI 
使用专门的存储区域网成本很高,而利用普通的数据网来传输SCSI数据实现和SAN相似的功能可以大大的降低成本,同时提高系统的灵活性。iSCSI就是这样一种技术,它利用普通的TCP/IP网来传输本来用存储区域网来传输的SCSI数据块。iSCSI的成本相对SAN来说要低不少。随着千兆网的普及,万兆网也逐渐的进入主流,使iSCSI的速度相对SAN来说并没有太大的劣势。iSCSI目前存在的主要问题是:(1)新兴的技术,提供完整解决方案的厂商较少,对管理者技术要求高;(2)通过普通网卡存取iSCSI数据时,解码成SCSI需要CPU进行运算,增加了系统性能开销,如果采用专门的 iSCSI网卡虽然可以减少系统性能开销,但会大大增加成本;(3)使用数据
网络进行存取,存取速度冗余受网络运行状况的影响。 
    

        通过以上分析,下表总结了这四种方式的主要区别。 
通过以上比较研究,四种方案各有优劣。对于小型且服务较为集中的商业
企业,可采用简单的DAS方案。对于中小型商业企业,服务器数量比较少,有一定的数据集中管理要求,且没有大型数据库需求的可采用NAS方案。对于大中型商业企业,SAN和iSCSI是较好的选择。如果希望使用存储的服务器相对比较集中,且对系统性能要求极高,可考虑采用SAN方案;对于希望使用存储的服务器相对比较分散,又对性能要求不是很高的,可以考虑采用iSCSI方案。

Continue reading 【转】几种常见的网络存储技术的比较研究

【转】回车键触发表单提交的问题


回车键触发表单提交的问题

我们有时候希望回车键敲在文本框(input element)里来提交表单(form),但有时候又不希望如此。比如搜索行为,希望输入完关键词之后直接按回车键立即提交表单,而有些复杂表单,可能要避免回车键误操作在未完成表单填写的时候就触发了表单提交。
要控制这些行为,不需要借助JS,浏览器已经帮我们做了这些处理,这里总结几条规则:
1、如果表单里有一个type=”submit”的按钮,回车键生效。
2、如果表单里只有一个type=”text”的input,不管按钮是什么type,回车键生效。
3、如果按钮不是用input,而是用button,并且没有加type,IE下默认为type=button,FF默认为type=submit。
4、其他表单元素如textarea、select不影响,radio checkbox不影响触发规则,但本身在FF下会响应回车键,在IE下不响应。
5、type=”image”的input,效果等同于type=”submit”,不知道为什么会设计这样一种type,不推荐使用,应该用CSS添加背景图合适些。
实际应用的时候,要让表单响应回车键很容易,保证表单里有个type=”submit”的按钮就行。而当只有一个文本框又不希望响应回车键怎么办呢?我的方法有点别扭,就是再写一个无意义的文本框,隐藏起来 但是如果设置了submit tabindex=0,则会提交  。根据第3条规则,我们在用button的时候,尽量显式声明type以使浏览器表现一致。

Continue reading 【转】回车键触发表单提交的问题

C/S与B/S架构

为了区别于传统的C/S模式,才特意将其称为B/S模式。认识到这些结构的特征,对于系统的选型而言是很关键的。 
1、系统的性能 
在系统的性能方面,B/S占有优势的是其异地浏览和信息采集的灵活性。任何时间、任何地点、任何系统,只要可以使用浏览器上网,就可以使用B/S系统的终端。 
不过,采用B/S结构,客户端只能完成浏览、查询、数据输入等简单功能,绝大部分工作由服务器承担,这使得服务器的负担很重。采用C/S结构时,客户端和服务器端都能够处理任务,这虽然对客户机的要求较高,但因此可以减轻服务器的压力。而且,由于客户端使用浏览器,使得网上发布的信息必须是以HTML格式为主,其它格式文件多半是以附件的形式存放。而HTML格式文件(也就是Web页面)不便于编辑修改,给文件管理带来了许多不便。 
2、系统的开发 
C/S 结构是建立在中间件产品基础之上的,要求应用开发者自己去处理事务管理、消息队列、数据的复制和同步、通信安全等系统级的问题。这对应用开发者提出了较高的要求,而且迫使应用开发者投入很多精力来解决应用程序以外的问题。这使得应用程序的维护、移植和互操作变得复杂。如果客户端是在不同的操作系统上,C/S结构的软件需要开发不同版本的客户端软件。但是,与B/S结构相比,C/S技术发展历史更为“悠久”。从技术成熟度及软件设计、开发人员的掌握水平来看,C/S技术应是更成熟、更可靠的。 
3、系统的升级维护 
C/S系统的各部分模块中有一部分改变,就要关联到其它模块的变动,使系统升级成本比较大。B/S与C/S处理模式相比,则大大简化了客户端,只要客户端机器能上网就可以。对于B/S而言,开发、维护等几乎所有工作也都集中在服务器端,当企业对网络应用进行升级时,只需更新服务器端的软件就可以,这减轻了异地用户系统维护与升级的成本。如果客户端的软件系统升级比较频繁,那么B/S架构的产品优势明显——所有的升级操作只需要针对服务器进行,这对那些点多面广的应用是很有价值的,例如一些招聘网站就需要采用B/S模式,客户端分散,且应用简单,只需要进行简单的浏览和少量信息的录入。 
4、C/S 模式的优点和缺点 
★ C/S 模式的优点 
● 由于客户端实现与服务器的直接相连,没有中间环节,因此响应速度快。 
操作界面漂亮、形式多样,可以充分满足客户自身的个性化要求。 
● C/S结构的管理信息系统具有较强的事务处理能力,能实现复杂的业务流程。
★ C/S 模式的缺点 
● 需要专门的客户端安装程序,分布功能弱,针对点多面广且不具备网络条件的用户群体,不能够实现快速部署安装和配置。 
兼容性差,对于不同的开发工具,具有较大的局限性。若采用不同工具,需要重新改写程序。 
开发成本较高,需要具有一定专业水准的技术人员才能完成。 
5、B/S模式的优点和缺点 
★ B/S 模式的优点 
具有分布性特点,可以随时随地进行查询、浏览等业务处理。 
● 业务扩展简单方便,通过增加网页即可增加服务器功能。 
● 维护简单方便,只需要改变网页,即可实现所有用户的同步更新。 
● 开发简单,共享性强。 
★ B/S 模式的缺点 
● 个性化特点明显降低,无法实现具有个性化的功能要求。 
● 操作是以鼠标为最基本的操作方式,无法满足快速操作的要求。 
● 页面动态刷新,响应速度明显降低。 
● 无法实现本地分页缓存显示,给数据库访问造成较大的压力。 
功能弱化,难以实现传统模式下的特殊功能要求。



c/s,b/s混用
异地查询,浏览等,功能简单,数据量小,安全要求低的可通过b/s实现。
对于数据量大,功能复杂,安全要求高的则使用c/s实现。

Continue reading C/S与B/S架构

JAVA内存泄漏——内存泄漏原因和内存泄漏检测工具

摘要 
虽然Java虚拟机(JVM)及其垃圾收集器(garbage collector,GC)负责管理大多数的内存任务,Java软件程序中还是有可能出现内存泄漏。实际上,这在大型项目中 是一个常见的问题。避免内存泄漏的第一步是要弄清楚它是如何发生的。本文介绍了编写Java代码的一些常见的内存泄漏陷阱,以及编写不泄漏代码的一些最佳 实践。一旦发生了内存泄漏,要指出造成泄漏的代码是非常困难的。因此本文还介绍了一种新工具,用来诊断泄漏并指出根本原因。该工具的开销非常小,因此可以 使用它来寻找处于生产中的系统的内存泄漏。

垃圾收集器的作用

虽然垃圾收集器处理了大多数内存管理问题,从而使编程人员的生活变得更轻松了,但是编程人员还是可能犯错而导致出现内存问题。简单地说,GC循 环地跟踪所有来自“根”对象(堆栈对象、静态对象、JNI句柄指向的对象,诸如此类)的引用,并将所有它所能到达的对象标记为活动的。程序只可以操纵这些 对象;其他的对象都被删除了。因为GC使程序不可能到达已被删除的对象,这么做就是安全的。

虽然内存管理可以说是自动化的,但是这并不能使编程人员免受思考内存管理问题之苦。例如,分配(以及释放)内存总会有开销,虽然这种开销对编程人员来说是不可见的。创建了太多对象的程序将会比完成同样的功能而创建的对象却比较少的程序更慢一些(在其他条件相同的情况下)。

而且,与本文更为密切相关的是,如果忘记“释放”先前分配的内存,就可能造成内存泄漏。 如果程序保留对永远不再使用的对象的引用,这些对象将会占用并耗尽内存,这是因为自动化的垃圾收集器无法证明这些对象将不再使用。正如我们先前所说的,如 果存在一个对对象的引用,对象就被定义为活动的,因此不能删除。为了确保能回收对象占用的内存,编程人员必须确保该对象不能到达。这通常是通过将对象字段 设置为null或者从集合(collection)中移除对象而完成的。但是,注意,当局部变量不再使用时,没有必要将其显式地设置为null。对这些变 量的引用将随着方法的退出而自动清除。

概括地说,这就是内存托管语言中的内存泄漏产生的主要原因:保留下来却永远不再使用的对象引用。

典型泄漏

既然我们知道了在Java中确实有可能发生内存泄漏,就让我们来看一些典型的内存泄漏及其原因。

全局集合

在大的应用程序中有某种全局的数据储存库是很常见的,例如一个JNDI树或一个会话表。在这些情况下,必须注意管理储存库的大小。必须有某种机制从储存库中移除不再需要的数据。

这可能有多种方法,但是最常见的一种是周期性运行的某种清除任务。该任务将验证储存库中的数据,并移除任何不再需要的数据。

另一种管理储存库的方法是使用反向链接(referrer)计数。然后集合负责统计集合中每个入口的反向链接的数目。这要求反向链接告诉集合何时会退出入口。当反向链接数目为零时,该元素就可以从集合中移除了。

缓存

缓存是一种数据结构,用于快速查找已经执行的操作的结果。因此,如果一个操作执行起来很慢,对于常用的输入数据,就可以将操作的结果缓存,并在下次调用该操作时使用缓存的数据。

缓存通常都是以动态方式实现的,其中新的结果是在执行时添加到缓存中的。典型的算法是:

检查结果是否在缓存中,如果在,就返回结果。 
如果结果不在缓存中,就进行计算。 
将计算出来的结果添加到缓存中,以便以后对该操作的调用可以使用。 
该算法的问题(或者说是潜在的内存泄漏)出在最后一步。如果调用该操作时有相当多的不同输入,就将有相当多的结果存储在缓存中。很明显这不是正确的方法。

为了预防这种具有潜在破坏性的设计,程序必须确保对于缓存所使用的内存容量有一个上限。因此,更好的算法是:

检查结果是否在缓存中,如果在,就返回结果。 
如果结果不在缓存中,就进行计算。 
如果缓存所占的空间过大,就移除缓存最久的结果。 
将计算出来的结果添加到缓存中,以便以后对该操作的调用可以使用。 
通过始终移除缓存最久的结果,我们实际上进行了这样的假设:在将来,比起缓存最久的数据,最近输入的数据更有可能用到。这通常是一个不错的假设。

新算法将确保缓存的容量处于预定义的内存范围之内。确切的范围可能很难计算,因为缓存中的对象在不断变化,而且它们的引用包罗万象。为缓存设置正确的大小是一项非常复杂的任务,需要将所使用的内存容量与检索数据的速度加以平衡。

解决这个问题的另一种方法是使用java.lang.ref.SoftReference类跟踪缓存中的对象。这种方法保证这些引用能够被移除,如果虚拟机的内存用尽而需要更多堆的话。

ClassLoader

Java ClassLoader结构的使用为内存泄漏提供了许多可乘之机。正是该结构本身的复杂性使ClassLoader在内存泄漏方面存在如此多的问题。 ClassLoader的特别之处在于它不仅涉及“常规”的对象引用,还涉及元对象引用,比如:字段、方法和类。这意味着只要有对字段、方法、类或 ClassLoader的对象的引用,ClassLoader就会驻留在JVM中。因为ClassLoader本身可以关联许多类及其静态字段,所以就有 许多内存被泄漏了。

确定泄漏的位置

通常发生内存泄漏的第一个迹象是:在应用程序中出现了OutOfMemoryError。这通常发生在您最不愿意它发生的生产环境中,此时几乎 不能进行调试。有可能是因为测试环境运行应用程序的方式与生产系统不完全相同,因而导致泄漏只出现在生产中。在这种情况下,需要使用一些开销较低的工具来 监控和查找内存泄漏。还需要能够无需重启系统或修改代码就可以将这些工具连接到正在运行的系统上。可能最重要的是,当进行分析时,需要能够断开工具而保持 系统不受干扰。

虽然OutOfMemoryError通常都是内存泄漏的信号,但是也有可能应用程序确实正在使用这么多的内存;对于后者,或者必须增加JVM 可用的堆的数量,或者对应用程序进行某种更改,使它使用较少的内存。但是,在许多情况下,OutOfMemoryError都是内存泄漏的信号。一种查明 方法是不间断地监控GC的活动,确定内存使用量是否随着时间增加。如果确实如此,就可能发生了内存泄漏。

详细输出

有许多监控垃圾收集器活动的方法。而其中使用最广泛的可能是使用-Xverbose:gc选项启动JVM,并观察输出。

[memory ] 10.109-10.235: GC 65536K->16788K (65536K), 126.000 ms 
箭头后面的值(本例中是16788K)是垃圾收集所使用的堆的容量。

控制台

查看连续不断的GC的详细统计信息的输出将是非常乏味的。幸好有这方面的工具。JRockit Management Console可以显示堆使用量的图示。借助于该图,可以很容易地看出堆使用量是否随时间增加。
diyblPic 
Figure 1. The JRockit Management Console

甚至可以配置该管理控制台,以便如果发生堆使用量过大的情况(或基于其他的事件),控制台能够向您发送电子邮件。这明显使内存泄漏的查看变得更容易了。

内存泄漏检测工具

还有其他的专门进行内存泄漏检测的工具。JRockit Memory Leak Detector可以用来查看内存泄漏,并可以更深入地查出泄漏的根源。这个强大的工具是紧密集成到JRockit JVM中的,其开销非常小,对虚拟机的堆的访问也很容易。

专业工具的优点

一旦知道确实发生了内存泄漏,就需要更专业的工具来查明为什么会发生泄漏。JVM自己是不会告诉您的。这些专业 工具从JVM获得内存系统信息的方法基本上有两种:JVMTI和字节码技术(byte code instrumentation)。Java虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)及其前身Java虚拟机监视程序接口(Java Virtual Machine Profiling Interface,JVMPI)是外部工具与JVM通信并从JVM收集信息的标准化接口。字节码技术是指使用探测器处理字节码以获得工具所需的信息的技 术。

对于内存泄漏检测来说,这两种技术有两个缺点,这使它们不太适合用于生产环境。首先,它们在内存占用和性能降低 方面的开销不可忽略。有关堆使用量的信息必须以某种方式从JVM导出,并收集到工具中进行处理。这意味着要为工具分配内存。信息的导出也影响了JVM的性 能。例如,当收集信息时,垃圾收集器将运行得比较慢。另外一个缺点是需要始终将工具连在JVM上。这是不可能的:将工具连在一个已经启动的JVM上,进行 分析,断开工具,并保持JVM运行。

因为JRockit Memory Leak Detector是集成到JVM中的,就没有这两个缺点了。首先,许多处理和分析工作是 在JVM内部进行的,所以没有必要转换或重新创建任何数据。处理还可以背负(piggyback)在垃圾收集器本身上而进行,这意味着提高了速度。其次, 只要JVM是使用-Xmanagement选项(允许通过远程JMX接口监控和管理JVM)启动的,Memory Leak Detector就可以与运行中的JVM进行连接或断开。当该工具断开时,没有任何东西遗留在JVM中,JVM又将以全速运行代码,正如工具连接之前一 样。

趋势分析

让我们深入地研究一下该工具以及它是如何用来跟踪内存泄漏的。在知道发生内存泄漏之后,第一步是要弄清楚泄漏了 什么数据--哪个类的对象引起了泄漏?JRockit Memory Leak Detector是通过在每次垃圾收集时计算每个类的现有对象的数目来实现这一步的。如果特定类的对象数目随时间而增长(“增长率”),就可能发生了内存 泄漏。

diyblPic 
图2. Memory Leak Detector的趋势分析视图

因为泄漏可能像细流一样非常小,所以趋势分析必须运行很长一段时间。在短时间内,可能会发生一些类的局部增长, 而之后它们又会跌落。但是趋势分析的开销很小(最大开销也不过是在每次垃圾收集时将数据包由JRockit发送到Memory Leak Detector)。开销不应该成为任何系统的问题——即使是一个全速运行的生产中的系统。

起初数目会跳跃不停,但是一段时间之后它们就会稳定下来,并显示出哪些类的数目在增长。

找出根本原因

有时候知道是哪些类的对象在泄漏就足以说明问题了。这些类可能只用于代码中的非常有限的部分,对代码进行一次快 速检查就可以显示出问题所在。遗憾地是,很有可能只有这类信息还并不够。例如,常见到泄漏出在类java.lang.String的对象上,但是因为字符 串在整个程序中都使用,所以这并没有多大帮助。

我们想知道的是,另外还有哪些对象与泄漏对象关联?在本例中是String。为什么泄漏的对象还存在?哪些对象 保留了对这些对象的引用?但是能列出的所有保留对String的引用的对象将会非常多,以至于没有什么实际用处。为了限制数据的数量,可以将数据按类分 组,以便可以看出其他哪些对象的类与泄漏对象(String)关联。例如,String在Hashtable中是很常见的,因此我们可能会看到与 String关联的Hashtable数据项对象。由Hashtable数据项倒推,我们最终可以找到与这些数据项有关的Hashtable对象以及 String(如图3所示)。

diyblPic 
图3. 在工具中看到的类型图的示例视图

倒推

因为我们仍然是以类的对象而不是单独的对象来看待对象,所以我们不知道是哪个Hashtable在泄漏。如果我 们可以弄清楚系统中所有的Hashtable都有多大,我们就可以假定最大的Hashtable就是正在泄漏的那一个(因为随着时间的流逝它会累积泄漏而 增长得相当大)。因此,一份有关所有Hashtable对象以及它们引用了多少数据的列表,将会帮助我们指出造成泄漏的确切Hashtabl。

diyblPic 
图4. 界面:Hashtable对象以及它们所引用数据的数量的列表

对对象引用数据数目的计算开销非常大(需要以该对象作为根遍历引用图),如果必须对许多对象都这么做,将会花很 多时间。如果了解一点Hashtable的内部实现原理就可以找到一条捷径。Hashtable的内部有一个Hashtable数据项的数组。该数组随着 Hashtable中对象数目的增长而增长。因此,为找出最大的Hashtable,我们只需找出引用Hashtable数据项的最大数组。这样要快很 多。

diyblPic 
图5. 界面:最大的Hashtable数据项数组及其大小的清单

更进一步

当找到发生泄漏的Hashtable实例时,我们可以看到其他哪些实例在引用该Hashtable,并倒推回去看看是哪个Hashtable在泄漏。

diyblPic 
图 6. 这就是工具中的实例图

例如,该Hashtable可能是由MyServer类型的对象在名为activeSessions的字段中引用的。这种信息通常就足以查找源代码以定位问题所在了。

diyblPic 
图7. 检查对象以及它对其他对象的引用

找出分配位置

当跟踪内存泄漏问题时,查看对象分配到哪里是很有用的。只知道它们如何与其他对象相关联(即哪些对象引用了它 们)是不够的,关于它们在何处创建的信息也很有用。当然了,您并不想创建应用程序的辅助构件,以打印每次分配的堆栈跟踪(stack trace)。您也不想仅仅为了跟踪内存泄漏而在运行应用程序时将一个分析程序连接到生产环境中。

借助于JRockit Memory Leak Detector,应用程序中的代码可以在分配时进行动态添加,以创建堆栈跟踪。这些堆栈跟踪可以在工具中进行累积和分析。只要不启用就不会因该功能而产 生成本,这意味着随时可以进行分配跟踪。当请求分配跟踪时,JRockit 编译器动态插入代码以监控分配,但是只针对所请求的特定类。更好的是,在进行数据分析时,添加的代码全部被移除,代码中没有留下任何会引起应用程序性能降 低的更改。

diyblPic 
图8. 示例程序执行期间String的分配的堆栈跟踪

结束语

内存泄漏是难以发现的。本文重点介绍了几种避免内存泄漏的最佳实践,包括要始终记住在数据结构中所放置的内容,以及密切监控内存使用量以发现突然的增长。

我们都已经看到了JRockit Memory Leak Detector是如何用于生产中的系统以跟踪内存泄漏的。该工具使用一种三步式的方法来找出泄漏。首先,进行趋势分析,找出是哪个类的对象在泄漏。接下 来,看看有哪些其他的类与泄漏的类的对象相关联。最后,进一步研究单个对象,看看它们是如何互相关联的。也有可能对系统中所有对象分配进行动态的堆栈跟 踪。这些功能以及该工具紧密集成到JVM中的特性使您可以以一种安全而强大的方式跟踪内存泄漏并进行修复

我在这里举个例子:

java.lang.OutOfMemoryError这个错都见过,这就是内存泄露的结果。

在effective java item6中 讲了如下的例子:

public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
elements = new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e) {
ensureCapacity();
elements[size++] = e;
}
public Object pop() {
if (size == 0)
throw new EmptyStackException();
return elements[—size]; //这里仍存在对pop出去对象的强引用,问题来了
}
/**
* Ensure space for at least one more element, roughly
* doubling the capacity each time the array needs to grow.
*/
private void ensureCapacity() {
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}

应该修改如下:

public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}

内存泄露(Memory Leak)还有个名称叫做

unintentional object retentions 非故意对象闭留

Continue reading JAVA内存泄漏——内存泄漏原因和内存泄漏检测工具

在ie下,button 标记恐怕还存在几个不大不小的问题。

在ie下,<button>标记恐怕还存在几个不大不小的问题。

  1. 在一个表单里,如果有一个以上"submit"类型的<button>标签存在,在表单被提交时,不管你点击哪个<button>,所有<button>的值都会被post/get。
  2. <button>的缺省type属性被设置为"button",但是在A级别浏览器下,应该设置为"submit"才对
  3. 如果你用javascript去访问<button>的value属性,IE却返回了<button>的innerHTML属性,很让人恼火。 (可以使用"getAttributeNode"方法来避免.)

例如,一段HTML:

CODE:
  1. <form>
  2. <button type="submit" value="1" name="action-1">text 1</button>
  3. <button type="submit" value="2" name="action-2">text 2</button>
  4. </form>

在IE下,上面两个button的数据都会被提交。并且ie会提交这两个button的innerText而不是value。而其它浏览器仅仅提交你点击的那个button。

Continue reading 在ie下,button 标记恐怕还存在几个不大不小的问题。

VV 评审指南

 

评审指南

1.      目的

指导相关人员进行评审的规范流程,预先发现开发和管理中的问题,以便于处理。

2.   范围

本文档应结合《验证过程文件》使用。

本文档适用于公司内部所有软件项目/产品的评审活动。

同行评审的适用范畴:适用于对项目过程中工作产品的评审,如需求评审、设计评审、技术解决方案评审、程序设计评审、变更评审等。
    管理评审的适用范畴:适用于对项目过程中管理活动的评审,如项目计划评审、里程碑评审、阶段性评审等。

单人评审的适用范畴:适用于工作产品是简单明了的,不可能有很多缺陷,而且也不是非常关键的评审,如代码检查、测试用例评审、测试观点评审、测试报告评审等。

3.   输入

待评审产品
评审检查表

与评审有关的软件过程及标准

4.   定义

同行评审:Peer Review(简称PR),由软件工作产品创建者的同行们检查该工作产品,识别产品的缺陷,改进产品的不足。

管理评审:由软件项目/产品管理者对项目过程中管理活动进行评估,识别过程缺陷,改进管理活动。

单人评审:由单独一个评审员对简单的工作产品进行评估,识别产品的缺陷,改进产品的不足。

代码检查:检查编写好的程序代码,发现不符合编码规范、不能实现设计要求的的问题,改进代码的质量

PM主管(Project Manager)

PL:项目经理(Project Leader)

SL:项目小组长(Sub- Leader)

QA:品质保证人员(Quality Assurance

QC:品质控制人员(Quality Control)

 

5.   职责与角色

5.1           同行评审中的角色和职责

 

角  色

职             责

评审组

接受过有关如何进行评审的培训,负责本次正式评审的组织,主持正式评审会议;

保证行动项和建议得到文档化; 跟踪与确认正式评审所提出行动项的落实;

报告评审的结果; 收集和报告同行评审所需数据.

项目经理

安排评审计划(是项目计划的一部分),并参与所有的主要文件评审.

QA

协助安排计划类正式评审,保证评审按照评审规程进行.(注:纯技术类评审QA可不参加)。

记录员/协调员

评审前准备材料;使用评审单,用标准化的形式对评审会议中提出的问题和缺陷进行记录,同时需要记录行动项和建议,并将记录结果的评审单原件交给评审组;将评审单电子文档化后提交给所有评审员.

作者

宣读作品、可提出初步问题进行评审、快速解决所有确定的问题、保持客观,避免抵抗态度。

 

5.2           管理评审中的角色和职责

 

角  色

职             责

项目主管

应定期或在遇到重大问题时对项目进展状况、遇到问题、质量管理状况、存在风险进行评审,并主持评审会议。

项目经理

应定期或在遇到重大问题时对项目进展状况、遇到问题、质量管理状况、存在风险进行评审。

QA

负责向项目经理报告质量管理的运行状况、对纠正和预防措施执行跟踪和验证。

小组负责人

负责小组内部状况报告、提供管理评审所需的相关资料;针对评审中提出的问题包括可能出现的问题,负责提出并组织采取纠正和预防措施。

记录员/协调员

对评审会议中提出的问题和项目情况进行记录,同时需要记录行动项和建议,并将记录结果电子文档化后提交给相关利益者;

 

5.3           单人评审中的角色和职责

 

角  色

职             责

项目经理

确定哪些工作产品可进行单人评审,指定评审员。跟踪缺陷直到其得到解决

评审员

接受过有关如何进行评审的培训,执行评审,保证行动项和建议得到文档化; 跟踪与确认评审所提出行动项的落实;

报告评审的结果; 收集和报告评审所需数据.

作者

宣读作品、快速解决所有确定的问题、保持客观,避免抵抗态度。记录评审结果。

 

6.   入口准则

Ø        评审组长被任命。

Ø        评审在相关计划中被定义。

Ø        被评审的产品准备就绪。

Ø        评审员经过评审规程的培训。

Ø        评审员应经过被评审问题的技能的培训。

Ø        协调员应当受过如何执行评审的正式培训,或者应当参加几次评审的经验。

Ø        《项目计划》已经制定。

7.   评审准则

7.1           同行评审准则

1)评审产品,而不是评审设计者(不能使设计者有任何压力);

2)会场要有良好的气氛;

3)限制争论与反驳(评审会不是为了解决问题,而是为了发现问题);

4)指明问题范围,而不是解决提到的问题;

5)展示记录(最好有黑板,将问题随时写在黑板上);

6)组评审时会议人数应在5-9人为佳;

7)组评审时评审员中应包括被评审产品作者的同行。(例如对程序设计文档的评审,评审员中应包括其他程序设计人员);

8)组评审时评审员中应包括被评审产品的上下游相关人员。(例如对程序设计文档的评审,评审员中应包括详细设计人员和后续的编码人员);

9)坚持会前准备工作;

10)            对全部评审人员进行必要的培训;

7.2           管理评审准则

1)评审产品,而不是评审设计者(不能使设计者有任何压力);

2)指明问题范围,而不是解决提到的问题;

3)评审人员接受过关于评审的必要的培训;

4)评审人员在被评审产品领域具有丰富经验;

7.3           单人评审准则

1)评价项目总体情况和进展状况;

2)评价小组内部的进度和人员状况;

3)评价项目质量控制情况;

4)评价项目进展中遇到的问题并提出解决办法;

5)评价项目当前存在的风险;

6)评价其他情况(视项目阶段而定)

8.   评审步骤

8.1           同行评审

步骤一:制定评审计划
    项目经理在项目策划阶段制定评审计划.
步骤二:评审准备
    1、按照项目计划,在评审会议的一天前(该时间越长越好),由项目经理识别必须参与评审的评审员、并指定记录员、评审会议主持人,然后通知相关利益者。在通常情况下,与项目整体相关的评审,主持人为PL;对于各个模块的评审,主持人为SL。

2、需要提前进行申请的,应至少提前半天向SL提出评审申请(同时要提交需要评审的工作产品)。SL根据项目的进度计划,确定评审会议的具体时间。
    3、由项目经理指定相应的评审员,确定评审相关输入,并确定准备就绪的准则.
    4、在评审会议的前一天将评审通知、待评审材料以及相关的参考资料发给每个评审员,以保证评审员有足够的时间来预审文件. 预定会议的场所等,评审通知的分发可采取邮件等形式。
    5、如果决定取消或推迟会议,需要重新通知所有相关利益者.

6.各评审员依据《评审检查表》对待评审材料进行预审。预审中发现的问题写入《评审检查表》对应的检查点后“备注”栏,如过发现的问题与对应的检查点无关,可在检查表下方填写。
步骤三:评审会议

    由主评审人掌握会议节奏和主持会议.

1、评审工作产品的担当者,对工作产品进行讲解,对评审组成员提出的问题进行解答。

2、对评审中提出的每一个问题必须要有明确的结论。

3、确定问题的修改者和确认者。修改者需要给出调查问题的时间。
    4、由评审员发现问题,并讨论确认;记录员对评审结果进行记录(包括缺陷,行动项和建议).记录写入《评审记录与报告》,其中发现的缺陷分类应依客户要求进行分类,客户无要求应参考《缺陷分类标准》

5、对评审的工作产品依据评审的标准做出结论。

(1)评审的标准(建议:可以按照项目组的规定或者项目组根据情况进行调整):存在的严重缺陷(问题)≤n个(0 =< n <= 10)时可以认为通过评审。
    6、评审结束前,记录员复述所有缺陷,并由评审员进行缺陷分类.
    7、评审完成时,得出结论是否通过评审. 若不通过评审,则确定下一次评审会议的时间.

(1)评审结论的分类:

l        评审通过

l        评审不通过,需要重新评审,要确定重新评审的时间

l        评审通过,但工作产品修改后需要进行Email(或其它方式)确认。

8、主评审人指定相关人员收集所有评审资料(评审通知, 评审检查表,评审材料等).

步骤四:对评审结果采取行动
    1、会议记录员整理会议内容,完成评审记录初稿。要求详细记录评审会中发现的问题,及讨论的结论。

2、会议记录员将评审记录的初稿提交会议的参与者进行确认。根据确认的情况修订评审记录,确认无误后,将评审记录发与参加会议的人员。
    3、由项目经理指定人员或文件作者对评审结果进行分析、确定问题解决计划、对工作产品进行返工,并记录《评审记录与报告》中返工的信息。

4、有《评审记录与报告》不能涵盖的内容需要记录时,由项目经理指定人员撰写《会议纪录》
步骤五:评审结果被跟踪直至完成
    评审结果跟踪处理方式如下:

评审结果

跟踪处理方式

通过

不作修改

稍作修改

1、由项目经理指定人员或者QC对返工结果进行跟踪直到关闭,并记录《评审记录与报告》中跟踪的信息.

2、确认者按照确定的时间对修改的问题进行确认,并将结果及时间填写到《评审记录与报告》中。

不通过

重新修正编制

组织复审


步骤六:提交和归档
    由项目经理指定人员将评审资料交由配置管理员归档.文件提交参见《配置管理指南》

8.2           单人评审

考虑到成本,如果工作产品有很多缺陷或比较关键,那么工作产品应该采取上述同行评审会议的形式。但是如果工作产品是简单明了的,不可能有很多缺陷,而且也不是非常关键,则建议采取单人评审的形式。

单人评审的形式类似于同行评审过程:

1.和项目经理协商后,作者确定评审员。

2.安排了评审后,评审员提前收到评审材料。

3.评审员采用检查表独立的评审工作产品并准备和作者的会议。

4.评审会议只有两个人参与——作者和评审员,在会议中产生缺陷记录(《评审记录与报告》中)。返工事项和行动项被记录和跟踪,以确保其被解决。

项目经理负责跟踪缺陷直到其得到解决。

代码检查、测试用例评审、测试观点评审、测试报告评审等可采用单人评审的形式。

8.3           管理评审

步骤一:制定评审计划

在项目策划阶段制定评审计划.

步骤二:评审准备

1、按照项目计划,在评审会议的一天前(该时间越长越好),由项目经理识别必须参与评审的评审员、并指定记录员,然后通知相关利益者。在通常情况下,项目管理评审主持人为PM。   
2、在评审会议的前一天将评审通知发给每个评审员,评审通知的分发可采取邮件、传真等形式.
3、如果决定取消或推迟会议,需要重新通知所有相关利益者.

步骤三:评审会议
1、由项目经理掌握会议节奏和主持会议.
2、由评审员发现问题,并讨论确认;记录员对评审结果进行记录(包括缺陷,行动项和建议). 记录写入《评审记录与报告》中。
3、评审结束前,记录员复述所有缺陷。

步骤四:对评审结果采取行动

1、会议记录员整理会议内容,完成评审记录初稿。要求详细记录评审会中发现的问题,及讨论的结论。

2、会议记录员将评审记录的初稿提交会议的参与者进行确认。根据确认的情况修订评审记录,确认无误后,将评审记录发与参加会议的人员。
3、由项目经理指定人员或文件作者对评审结果进行分析、确定问题解决方案和计划。

4、有《评审记录与报告》不能涵盖的内容需要记录时,由项目经理指定人员撰写《会议纪录》

步骤五:评审结果被跟踪直至完成
       评审结果跟踪处理方式如下:

评审结果

跟踪处理方式

通过

不作修改

稍作修改

1、由项目经理指定人员或者QC对返工结果进行跟踪直到关闭,并记录《评审记录与报告》中跟踪的信息.

2、确认者按照确定的时间对修改的问题进行确认,并将结果及时间填写到《评审记录与报告》中。

不通过

重新修正编制

组织复审

 

步骤六:提交和归档
由项目经理指定人员或者QC将评审资料交由配置管理员归档。

9.   出口准则

评审中发现的所有问题和缺陷都已经得到解决(关闭)。评审结论为“不通过”时要求一定要安排进行复审。

10. 裁剪

1.      工作产品是否需要进行评审可参考文件《验证确认区分表》

2.      评审通常应采用会议评审的形式,如果有特殊原因不能采用会议评审时,需由项目经理、项目主管共同批准认定。其他形式的评审,包括电子Email、网络视频、等方式,基本同样按照上述5.2内容中进行,另需对各联络的信件(电子信件)进行保存,对评审的结果以信件或其他方式通知参与评审的人员。

3.      必要时可以采用会签的方式最终确认评审结果,会签时应打印评审报告,由评审员手工签名确认。

11. 输出

已通过评审的产品
    评审通知,评审检查表,评审报告(评审缺陷列表、评审结论)

12. 度量

1)评审工作量

2)评审发现缺陷数

3)被评审产品缺陷率

Continue reading VV 评审指南

Oracle导出数据库结构到PowerDesigner

 

Oracle导出数据库结构到PowerDesigner:

具体的操作步骤:打开PowerDesigner-》菜单栏 “Database”-》Database Reverse Engineering-》Using an ODBC data source中选择右边的浏览-》connect to an ODBC Data Source-》在Machine data source中选择你配置好的数据源。

(注:如果第一次连接,需要先配置数据源,步骤如下:点击“Add”按钮,

-》ODBC数据源管理器-》点击“添加”按钮-》创建新数据源-》选择“Oracle in OraHome92” -》完成。

-》进入“Oracle ODBC Driver Configuration”-》配置数据源名称(Data Source Name)以及监听器(TNS Service Name)-》配置完成后点击右边的“Test Connection”。

-》在弹出框里输入连接数据库的用户名和密码-》点击OK-》提示Connection successful-》OK-》数据源配置成功。

-》退出数据源配置后,在数据源连接对话框中(Connect to an ODBC Data Source)中选择好刚才配置的数据源,然后再次填写用户名和密码。

-》点击connect,就可连接到数据库上。)

Continue reading Oracle导出数据库结构到PowerDesigner

什么叫n+1次select查询问题?

 

我说应该叫1 + N问题

在 Session的缓存中存放的是相互关联的对象图。默认情况下,当Hibernate从数据库中加载Customer对象时,会同时加载所有关联的 Order对象。以Customer和Order类为例,假定ORDERS表的CUSTOMER_ID外键允许为null,图1列出了CUSTOMERS 表和ORDERS表中的记录。

以下Session的find()方法用于到数据库中检索所有的Customer对象:

List customerLists=session.find("from Customer as c");

运行以上find()方法时,Hibernate将先查询CUSTOMERS表中所有的记录,然后根据每条记录的ID,到ORDERS表中查询有参照关系的记录,Hibernate将依次执行以下select语句:

select * from CUSTOMERS;
select * from ORDERS where CUSTOMER_ID=1;
select * from ORDERS where CUSTOMER_ID=2;
select * from ORDERS where CUSTOMER_ID=3;
select * from ORDERS where CUSTOMER_ID=4;

通过以上5条select语句,Hibernate最后加载了4个Customer对象和5个Order对象,在内存中形成了一幅关联的对象图,参见图2。

Hibernate在检索与Customer关联的Order对象时,使用了默认的立即检索策略。这种检索策略存在两大不足:

(1) select语句的数目太多,需要频繁的访问数据库,会影响检索性能。如果需要查询n个Customer对象,那么必须执行n+1次select查询语句。这就是经典的n+1次select查询问题。这种检索策略没有利用SQL的连接查询功能,例如以上5条select语句完全可以通过以下1条select语句来完成:

select * from CUSTOMERS left outer join ORDERS
on CUSTOMERS.ID=ORDERS.CUSTOMER_ID

以上select语句使用了SQL的左外连接查询功能,能够在一条select语句中查询出CUSTOMERS表的所有记录,以及匹配的ORDERS表的记录。

(2)在应用逻辑只需要访问Customer对象,而不需要访问Order对象的场合,加载Order对象完全是多余的操作,这些多余的Order对象白白浪费了许多内存空间。
为了解决以上问题,Hibernate提供了其他两种检索策略:延迟检索策略和迫切左外连接检索策略。延迟检索策略能避免多余加载应用程序不需要访问的关联对象,迫切左外连接检索策略则充分利用了SQL的外连接查询功能,能够减少select语句的数目。

Continue reading 什么叫n+1次select查询问题?

java执行groovy的方式

 

脚本全文(不需要包名匹配,因为这是脚本):

println("hello!this is a script!");

类全文:

package co.java;

import java.io.File;
import java.io.IOException;

import org.codehaus.groovy.control.CompilationFailedException;

import groovy.lang.GroovyClassLoader;
import groovy.lang.Script;
import groovy.util.GroovyScriptEngine;

public class InvokeGroovyTest
{
    public static void main(String[] args)
    {
        InvokeGroovyTest test = new InvokeGroovyTest();
       
//        test.way1();
        test.way2();
    }
   
    public void way1()
    {
        try
        {
            ClassLoader cl = InvokeGroovyTest.class.getClassLoader();
            GroovyClassLoader groovyCl = new GroovyClassLoader(cl);
            Class groovyClass = groovyCl.parseClass(new File("src/co/java/Script.groovy"));
            Script sc = (Script)groovyClass.newInstance();
            sc.run();
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
       
    }
   
    public void way2()
    {
        try
        {
            GroovyScriptEngine engine = new GroovyScriptEngine(".");
            engine.run("src/co/java/Script.groovy", (String)null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }       
    }
}

Continue reading java执行groovy的方式

Pagination


Total views.

© 2013 - 2020. All rights reserved.

Powered by Hydejack v6.6.1