测试目标:公司的struts2+spring+hibernate项目
测试环境:JDK1.5.0、TOMCAT5.5、SqlServer2000
测试原因:系统运行时发现内存不断增加,操作到达一定次数后PermGen space的outmemory错误。
测试工具:Jprofilter5.2.1检测内存情况
疑点一:
数据库连接池管理模块中有一个线程,运行期定期执行,检测池中连接状态。此线程每运行一次,内存增加5K-2M不等
主要代码:
分析:
Iterator iterator;
ConnectionPool pool;
两个对象在循环中,每次循环声明一次,造成每次申请一个新内存空间,使内存数量增加。但此内存空间可被gc释放,不是内存溢出的原因。
解决:以上两变量声明提到循环外
疑点二:
项目中所有action每执行一次,消耗内存若干,且不释放,所有action均继承自定义的BaseAction类,估计是BaseAction的问题。
分析:
写脚本单独运行BaseAction,并逐个去除其成员,最终确定造成内存溢出的是BaseAction的一个成员。
初次使用SSH框架,前期未作深入学习,只知道FileSystemXmlApplicationContext由spring提供,可用以创建ApplicationContext实例,而ApplicationContext实例可用于hibernate对象的创建,具体原理不明。
测试发现FileSystemXmlApplicationContext每生成一次,applicationContext.xml文件中配置的bean全部创建一次实例,估计是为注入做准备用,但使用完后,内存空间不释放,原因不明,猜测是spring内部机制。不过既然每次执行全部bean都被创建,估计此方法应该是为spring框架整体运行做准备使用的,而不是针对具体操作使用的,用在此处就不太合适了。
网上搜了一下,web应用中,spring提供了一个监听器org.springframework.web.context.ContextLoaderListener,用以初始化ApplicationContext对象,此对象实例贯穿项目运行始终,可使用WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);获得。
但ApplicationContext ctx 是BaseAction成员,创建BaseAction时ServletContext 尚未赋值,ServletContext sc为空,因此ctx无法获得对象。
最终解决:
增加静态变量Sys.ctx,在自定义监听中,执行
action中直接取用Sys.ctx。注意,自定义监听必须在监听器org.springframework.web.context.ContextLoaderListener
之后。
问题:不确定是否有线程冲突,目前自测情况暂无问题,如有问题,后续处理
本文介绍了在struts2+spring+hibernate项目中遇到的内存溢出问题,详细分析了数据库连接池管理模块导致的内存增长以及BaseAction类中的ApplicationContext引起的内存占用。通过调整代码,将循环内的局部变量移出,并使用静态变量存储ApplicationContext,有效解决了内存溢出问题。同时提出了可能存在的线程冲突风险及后续处理方案。

1593

被折叠的 条评论
为什么被折叠?



