session不及时释放导致内存溢出的性能问题分析

背景:

做一个网站的时候,发现服务器上一段时间特别不稳定,每隔一段时间就会报”OutOfMemoryError: PermGen space”错误,于是网站也就歇菜了.

部署环境:windows2003,tomcat6.0,spring mvc2.5

辅助分析工具:jprofile6,visualvm,mat

分析过程:

1.自我检查阶段。由于是报perm区异常,我首先想到,系统默认perm区太小,想想应该要调整perm区大小,打开catalina.bat,设置了JAVA_OPTS,

JAVA_OPTS="-server -Xms512m -Xmx2048m  -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=784m"

这样设置后,模拟歇菜时候的情况进行压力测试,发现蛮稳定的,没有出现什么问题,这时又仔细检查代码,根本就没有出现频繁创建不可回收的垃圾对象,于是就先这样吧。过了一段时间发现又出问题了,还是perm溢出。

接着我计算下perm区已经够大了,怎么还会报这个异常,此时非常迷茫中....

2.工具辅助分析。visualvm  利用visualvm看看perm区是否真的像传说中说的那样---"perm溢出了",

看来还是老实点用apache自带的工具做压力测试看看是不是这个地方引起的

测试工具用apache自带的  ./ab -n 100000 -c 40 http://www.tongzhuangweb.com/class/kw-童卫衣.html

40个并发的时候perm区在30m处跌停,基本保持0增长。看来和perm区没关系。

perm区

看下heap区发现问题了  40并发下到后来基本保持5分钟一次full gc了,这样开心啊,原来heap区出问题了,多个应用放在一个tomcat里的时候,如果一个应用正好这样了,

   

刚开始的heap,好像也没什么问题,郁闷了~~~继续迷茫~~~~只能等待,等着出问题吧...半个小时过去了,还是这样....

突然发现惊喜了。。。如图

内存占用居高不下,这下就好分析了

于是赶紧用jprofile看看是哪个类造反,赶紧收拾了,只能看到都是大对象map,也只有list页面的数据暴露在页面上的这个map最大,不过每次请求结束后应该都能自动回收掉吧,但是却回收不了,感觉有点奇怪,不应该啊~~~,但是又看不到是什么对象造成这么多大对象map...

3.定位问题。只能用mat工具分析了,过了好久,终于发现惊喜了,如图

原来有那么session霸占这map对象,网站根本就没有使用session,这么单纯的网站和session有啥关系呢,日了日了。。。我以前还一直以为只有动态存放session内容的时候,才会创建session对象,这下才明白一点...

Servlet协议描述如下:
getSession(boolean create)方法:

javax.servlet.http.HttpServletRequest.getSession(boolean create)

Returns the current HttpSession associated with this request or, if if there is no current session and create is true, returns a new session. 
If create is false and the request has no valid HttpSession, this method returns null. 
To make sure the session is properly maintained, you must call this method before the response is committed.

简单地说:当create变量为true时,如果当前Session不存在,创建一个新的Session并且返回.(session创建机制:http://daihaixiang.blog.163.com/blog/static/3830134201011110537275/)

4.解决问题。

仔细看了session创建机制和tomcat这部分的代码,发现可以设置session超时时间,试试设置了后会如何?结果如下

看到每5分钟出现一个小三角   好开心,说明有效果了    因为有部分session被和谐了,接着就要如何取消session了,在我这个只是没有用户管理之类功能的单纯网站来说把session和谐掉才是良策。org.apache.catalina.connector.Request.getSession(),最终调用的是doGetSession(boolean create)方法,这部分代码也告诉我们如何和谐session:

1.重写sessionManager 全部都和谐掉 然后修改Tomcat的配置文件 也可以做到的

2.调用request.getSession().invalidate(); 方法,具体为啥调用这段 代码,有兴趣可以看下Request.getSession()里的源码,这样可以达到不使用session

3.设置jsp页面session参数  <%@ page session="false" language="java" pageEncoding="UTF-8" %>

和谐了session后,发现这个问题就解决了,如图

正常了

你可能感兴趣的:(集群应用)