最近越来越关注j2ee程序性能的问题,怎样改善自己的代码,怎样对程序调优、怎样架构应用、怎样调整服务器等等,终于发现一篇,以后好好研究一下。
J2EE应用程序中的性能提升
--清除耗时且低效的bug
Java很热门,尽管只诞生了9年,但它已经成为世界上领先的开发环境之一。数百万的程序员和数千家公司都在使用它,而且半数IT管理者都希望在今年部署J2EE应用程序。
但是Java的流行并不一定使之对于日益增长的Java代码开发人员变得容易。为了在生产上达到一个新的高度,程序员们逐渐在更大的团队中工作,而在他们当中,持续缩短开发周期始终很热门。每天,那些团队都要面对一个软件开发中的不变定律:您编写的代码越多,您就会碰到越多的bug——而且是浪费时间和降低应用程序质量和性能的bug。
本文主要介绍了一个J2EE应用程序的性能调优和内存使用优化。我们设置使用 BEA WebLogic Application Server。我们将讨论以下几个方面:
问题域
我们有一个如下设置的J2EE应用程序:
问题
应用程序有一个内存问题。当服务器启动时,内存使用率大约占全部可用物理内存的7~8%。随着时间的推移和更多地使用应用程序,内存使用率会增加到接近49~53%(7~10天一个周期)。
如果用户通过点击左边菜单中的“Log off”按钮从他们的会话中注销,那么应用程序就会从服务器中删去所有的有状态bean。但是,如果一个用户仅仅只是关闭浏览器窗口,那它就不会删去那些bean,而会在容器中保留它们直到应用服务器重新启动为止。这样继续下去,内存中的EJB实例数量会增加到400个甚至更多。
当BEA WebLogic Server装载了多于400个EJB时,Hotspot虚拟机会抛出一个OutOfMemory 异常。尽管看似还有更多内存可用,但这种情况还是会发生。
调优Java虚拟机
当试图分配PermGeneration空间时,Hotspot虚拟机会抛出OutOfMemory异常。Hotspot虚拟机使用不同部分的内存。持久生成部分被用来储存类、方法以及运行的Java对象所使用的符号。持久生成部分的初始大小为1MB,最大值为64MB,1.3.1之前是32MB。
要避免这种情况,我们可以通过一个Java虚拟机开关,使用下面的命令行来设置permGeneration空间。
java -server -XX:MaxPermSize=128M.
注意,增加perm 最大值只是推迟了故障的发生。最终还是要靠您的应用程序去适当地清除无用的对象。另外,并非所有的Java虚拟机都支持XX选项。
HTTP Session 管理
当用户没有从会话中注销就关闭浏览器时,用户会话中的EJB不会被垃圾收集。这就是内存中有太多EJB的主要原因。要避免这种情况,HTTP session 管理必须注意所有可能的结合。我们可以在web.xml (Web应用程序部署描述符)中设置一个默认的会话超时周期,如下所示:
<session-config>
<session-timeout>x</session-timeout>
<session-config>
通过这个设置,用户的会话会在不活动x分钟后自动释放。
另一种方法是在创建HTTP session时用下面的代码编写会话管理
HttpSession session=new HttpSession ();
session.setmaxinactiveinternal(int timeoutSeconds);
这段代码会使不活动了timeoutSeconds时间的用户会话失效。
注意:如果您把两个步骤都做了,那么在servlet代码中的值将覆盖在web.xml中设置的值。
这两种方法惟一的不同点是第二种方法以秒作为参数,而 <session-timeout> 标记则是以分钟作为参数。通常,当会话失效后,logoff servlet/JSP 会用代码删去被特殊会话所引用的所有对象/对象图形的引用。但是当用户只是关闭浏览器时,就没有办法调用注销servlet/JSP。在这种情况下,即使会话已经失效,被封装的对象和对象图形会继续存在。当垃圾收集器试图对该会话进行垃圾收集时,它也会对所有这些封装对象进行收集。当我们有大对象时(拥有大的引用/数据的对象),我们也可以用HTTPSessionListener接口来进行同样的清除工作。
javax.servlet.http.HTTPSessionListener 接口
该接口声明了下面两种回调方法:
Public void sessionCreated(HttpSessionEvent event);
Public void sessionDestroyed(HttpSessionEven event);
这些方法在一个会话被创建/销毁前被调用。
我们可以使用一个实现了这个接口的监听器类,并用这些回调方法来控制会话的创建和销毁。我们需要像下面这样在web.xml中注册我们的监听器类:
<listener>
<listener-class>MySessionListener</listener-class>
</listener>
使用监听器类以及在web.xml文件中添加会话超时参数的好处是我们能对会话管理进行更多的控制。如果会话拥有大对象,那么在垃圾收集器清除这些对象之前,它的时间片可能会消失。在这种情况下,就需要等到下一个时间片才能清除这些对象。
注意:我们所设计的应用程序只有一个进入点是很重要的。我们需要在这个类中启动一个新的 HTTP session。所有余下的页面应该检查 HTTP session 是否存在,并且当会话为null时(Session 到期)调入一个错误页面。这样就可以实现对 HTTP session 的集中控制。
调优应用服务器
BEA WebLogic 提供了一些参数,我们能用它们优化bean池的大小,这包括设置无状态bean 池的初始大小。以下是一些使用方法:
例如,考虑下面的设置
<idle-timeout-seconds>1200</idle-timeout-seconds>
这个空闲bean实例将会在静止20分钟后被钝化。再过20分钟,这个bean实例会从硬盘上删去。现在,让我们假设在第41分钟用户调用了这个bean实例的一个方法。BEA WebLogic Server将会抛出错误,如程序清单1所示。
程序清单 1
: Bean has been deleted.
at weblogic.ejb20.swap.DiskSwap.read(DiskSwap.java:156) at
weblogic.ejb20.manager.StatefulSessionManager.getBean(StatefulSession Manager.java:242) at
weblogic.ejb20.manager.StatefulSessionManager.preInvoke(StatefulSessionManager.java:313)
at weblogic.ejb20.internal.BaseEJBLocalObject.preInvoke(BaseEJBLocalObject.java:113)
at
weblogic.ejb20.internal.StatefulEJBLocalObject.preInvoke(StatefulEJBLocalObject.java:126)
WebLogic 6.1 Service Pack 5提供了一个有用的标记来避免发生这种情况。这个标记如下所示:
<!-- The stateful session beans that are passivated to the disk will stay alive for this many seconds. After this interval, the passivated beans will be removed from the disk.
Used in: stateful-session-cache
Since: WebLogic Server 6.1 sp5
Default value: 600
-->
<! ELEMENT session-timeout-seconds (#PCDATA)>
如果我们为这个<session-timeout-seconds>设置值,我们就能控制钝化的bean何时从硬盘中被删去。我们可以使用这个标记并把它设置到一个适当的值,这样我们就能总是拥有有状态EJB(或者在内存中或者在硬盘中)。这将完全消除bean被删除的错误。
使用WebLogic被管理服务器
BEA WebLogic 允许您在单独一个域中创建一个或多个服务器。一个服务器是管理服务器,所有其它服务器是被管理服务器,也就是被管理服务器管理。一个应用程序投入使用后,不应该被部署在管理服务器上。使用被管理服务器的好处是我们能从管理控制台上启动和停止它们。因此,即使服务器使应用程序停止响应(任何的原因),我们还是可以有机会从管理控制台重新启动服务器。
编码标准:为未来放弃规则
当系统的运行环境并没有在设计阶段考虑到时,管理一个开发系统会更加困难。当在设计阶段认真考虑了环境、边界、应用程序的运行环境后,系统再开发将是一项简单的任务。设计是执行路径的抽象定义。当考虑了设计中的每一个细节后再开发,解决方案会更具可伸缩性。对于系统开发并没有硬性的规定,因为这取决于您正面对的特定问题域。但是,还是有一些总会有帮助的定律。
总之一句话,”尽可能晚的创建对象而尽可能早的删除它们”。
原文出处 http://www.sys-con.com/story/?storyid=43039&DE=1
<!---->