解决方法
方法如下:
我们从图形二中发现,在8.95(将近9点钟)到9.66(将近9点40)期间有几次Full GC,但是有内存泄漏,从占用率40%上升到50%左右,泄漏了大约10%的内存,约300M;
我们在自己搭建的Web应用服务器平台(应用软件版本和生产版本一致)做这一阶段相同的查询交易;表明对同一个黑盒(Web应用)施加同样的刺激(相同的操作过程和查询交易)以期重现现象;
我们使用Jprofiler工具对Web应用服务器的内存进行实时监控;
做完这些交易后,用户退出系统,并等待Web应用服务器的HttpSession超时(我们这里设置为15分钟);
我们对Web应用服务器做了两次强制性的内存回收操作。
发现如下:
图三
如图三所示,内存经过HttpSession超时后,并强制gc后,仍然有大量的对象没有释放。例如:gov.gdlt.taxcore.comm.security.MenuNode,仍然有807个实例没有释放。
我们继续追溯发现,这些MenuNode首先存放在一个ArrayList对象中,然后发现这个ArrayList对象又是存放在WHsessionAttrVO对象的Map中,WHsessionAttrVO 对象又是存放在ExternalSessionManager的staic Map中(名称为sessionMap),如图四所示。
图四
我们发现gov.gdlt.taxcore.taxevent.xtgl.comm.WHsessionAttrVO中保存了EJBSessionId信息(登录用户的唯一标志,由用户id+登录时间戳组成,每天都不同)和一个HashMap,这个HashMap中的内容有:
ArrayList: 内有MenuTreeNodes(菜单树节点)
HashMap: 内有操作人员代码信息
CurrentVersion:当前版本号
CurrentTime:当前系统时间
WHsessionAttrVO这个对象的最终存放在ExternalSessionManager的static Map sessionMap中,由于ExternalSessionManager是一个全局的单实例,不会释放,所以它的成员变量sessionMap中的数据也不会释放,而Map中的Key值为EJBSessionId,每天登录的用户EJBSessionId都不同,就造成了每天的登录信息(包括菜单信息)都保存在sessionMap中不会被释放,最终造成了内存的泄漏。
图五
如上图所示:WHsessionAttrsVO对象中除了有一个String对象(内容是EJBSessionId),还有一个HashMap对象。
图六
如上图所示,这个HashMap中的内容主要有menuTreeNodes为key,value为ArrayList的对象和以czrydminfo为key,value为HashMap对象的数据。
图七
如上图所示:menuTreeNodes为key,value为ArrayList对象中包含的对象有许多的MenuNode对象,封装的都是用户的菜单节点。
图八
如上图所示,最顶层(Root)的初始对象为一个ExternalSessionManager对象,其中的一个成员变量为static (静态的),名称为:sessionMap,这个对象是singleton方式的,全局只有一个。