关于hibernate导致tomcat内存暴涨,页面反应速度减慢

2012年6月23日

今天追踪一个关于页面内存暴涨,页面响应过慢的问题。花了4个多小时,总算找到问题出在哪了。

一、问题描述

最近我们在一台独享服务器上搭建了Tomcat6.0.19环境,发现访问首页时,内存暴涨,一直不退。每次刷新内存增加近10M。一个人狂刷新一分钟就可以把tomcat搞死机。

然后,找各种办法解决问题。整了几天,每天中午轮流监控Tomcat服务器,发现它挂了后就重启。累坏了。

每天到google上面搜索答案,有人说是程序的问题,程序内存泄露。甚至问到“有没有数据库没有释放”、“有没有使用死循环”、有没有写“System.gc()自动释放内存”、有没有“在Service层查询时使用all()方法,查处了所有记录”。等等。

而我一直不承认程序有问题。理由是:我们曾经将这个程序在租用的2个虚拟主机中用了近1个月。不断维护,最后达到一个星期没有出现一个异常的情况。

二、问题分析(关于tomcat内存溢出问题)

分析Tomcat死机的日志,发现是内存耗尽。

大致有这么一段,PSPermGen total   86016K   used 86015K   

到网上搜了一下,明白了jvm内存分类。然后配置内存,让tomcat自动回收jvm内存。

当然,配置过程也遇到了很多问题,花了一天多。问题是网上的很多人都是抄来抄去,要在一大堆垃圾中选出精品不容易呀。

配了一天都只起到一定作用。比如:给tomcat设置较大内存后,tomcat可以承受到2.19G。只是再刷新就可以把他整崩溃。

最后,请了几个牛人帮忙,一个牛人凌晨帮我们看tomcat配置。问我们,是否加了,-server参数。最后,我同事加上了-server参数。 然后,回去睡觉了,发现java.exe内存真的能回收了。很多问题也解决了。

我们配置如下:(将tomcat6的安装版卸载,换成绿色版)

在catalina.bat的@echo off下面添加(就是第二行)

set JAVA_OPTS=-server -Xms512m -Xmx1024m -XX:MaxNewSize=512m -XX:MaxPermSize=256m 

在startup.bat下面添加(让tomcat的工具自动回收内存)

@echo off
set JAVA_OPTS=%JAVA_OPTS%
-Dcom.sun.management.jmxremote.port=1090
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file="%CATALINA_HOME%\conf\logging.properties"

三、问题分析(关于页面反应速度异常)

我们的首页显示餐馆的信息,主要根据用户选择地区,然后将该地区的餐馆列表和热卖美食列表显示出来。我们发现一个很奇怪的现象,访问某一学校东校区时:

8个餐馆:Action执行2063ms(获取餐馆列表:1220ms + 获取热卖美食:825ms)。

然后换成其他校区分别为:

3个餐馆:Action执行 51ms   (获取餐馆列表:29    +    获取热卖美食: 2)

3个餐馆:Action执行 53ms   (32   + 1)

4个餐馆:Action执行 90ms   (74    + 1)

看到这个数据,我就很纳闷,怎么时间不成比例呢?

于是,我将8个餐馆删掉4个对比。由于有外键关联,我必须要删除其他的很多的。为了删除一个餐馆记录,我必须删除其他记录多达6个表处,可见外键关系较为复杂。

等我删掉后,发现东校区:

4个餐馆:Action执行111ms(获取餐馆列表:53ms + 获取热卖美食:37ms)。

我发现这个变化太明显了吧。然后,我怀疑那四个餐馆关联了太多东西。我查询出来的不仅仅是餐馆,可能连带查询了另外的6个表的记录。

我就想到了是hbm.xml文件中设置lazy = "true"问题。

通过测试,我发现是 餐馆对应订单时,one-to-many时,lazy = "true"。这个就很明显了。

查询一个餐馆,就把它的上百份订单级联查询出来了,同时把所有菜品也级联查询出来了,把所有菜品分类都查询出来了。

而就东校区的这8家餐馆订单较多,其他校区由于刚开业,订单几乎没有。这下就可以解释为什么东校区这么耗时间(当然也耗内存)。

然后,我将hbm.xml的所有lazy="true"全部去掉,恢复数据库数据。

东校区结果如下:

8个餐馆:Action执行25ms(获取餐馆列表:3ms + 获取热卖美食:8ms)。

四、结论:

        lazy="false"使用时要慎重。例如:对与1:1的情况,使用直接影响不大,对于1:n情况就要慎重了。尤其是n成百上千时,问题就相当严重了。我建议最好不用。

第一次,配置和管理服务器,收获真大呀。对我以后的编程风格都造成了深远的影响。我会注意服务器的时间和空间效率问题。

当然测试方法比较土。先将服务器正常上线后,我会学着使用JMeter和roadrunner的工具做压力测试,配置好服务器。

忙里偷闲!记录下来!

posted on 2012-06-23 16:50  垦荒牛  阅读(1502)  评论(0编辑  收藏  举报