最近做一个项目,环境是struts2.3.16,spring3.0,mybatis2.3
当我使用JQuery的ajax方法提交请求返回个对象时,遇到了内存泄露的问题,这个问题困扰了我一个多星期:
开始调用ajax方法,反应比较慢,大概4~5秒之后才会出现效果.
重复几次调用之后,浏览器直接崩溃,系统开始卡,一步一卡...
打开cpu监视情况发现,当调用ajax方法,内存从百分之56直接飞到87..
随之MyEclipse后台爆出java.lang.OutOfMemoryError: PermGen space...
找了N久..在其他人机器上运行结果一样...郁闷~马上要交货, 查阅很多相关文章,最终确定是自己代码问题, 与环境无关,仔细将代码检查了2遍,没有发现任何不符合常规的问题....
突然意识到一个问题, 项目使用的是mybatis框架,在Mybatis中配置resultMap是可以配置关联查询的..而在传递数据是采用Josn格式传递.
使用josn需要注意的一个问题就是一定要避免复合结构数据死循环..
比如班级(Classes),学生(Student)两个类, 在Classes一方有list<Student> students属性,而在Student中有Classes classess属性,
他们直接互相存在对方的引用,当使用josn传递数据,就会出现无限级查询的死循环..所传递的Josn数据也是异常庞大...
对自己项目中,因为使用的struts2做控制器,所以在使用jquery调用ajax时,我是直接通过struts2集成的josn(偷懒),代码如下:
ajax,一个动态级联请求方法:
$(‘#companySelect‘).change(function(){ var deptId=$(this).val(); var sendData={‘deptId‘:deptId};//数据 josn格式数据 var url="user!searSecondSelect";//地址 $.ajax({//写法是josn格式的 url:url,//地址 data:sendData,//参数 type:‘post‘,//设置提交类型 success:function(data){//请求成功的回调函数 var value=‘<option value="0">--请选择部门--</option>‘; for(var i=0;i<data.deptlist.length;i++){ value+=‘<option value="‘+data.deptlist[i].deptId+‘">‘+data.deptlist[i].deptName+‘</option>‘ } $(‘#deptIdSelect‘).html(value); } }); });
请求方法代码: 通过查询数据库,将结果放入相应的封装好属性中(deptlist).
public String searSecondSelect(){ this.setDeptlist(ds.selectAll(deptId)); return "searchTwoDept"; }
struts.xml配置:通过继承json-default包来传递josn数据
<package name="zhanglu" namespace="/" extends="json-default"> <action name="user" class="userAction"> <result name="success">/Permission/user_manage.jsp</result> <result name="exits">/Permission/Exits.jsp</result> <result name="postInfo" type="json"></result> <result name="searchTwoDept" type="json"></result> </action> </package >
整个ajax请求到回调函数,没有任何问题,运行一切ok..
可是在另一个ajax方法中就出现内存溢出,我需要查询一个员工信息对象(employee)返回在页面显示,试过很多的方法, 最终决定换一种josn传递方式,不使用struts2的json-default方式,另一种写法如下:
ajax方法.请求一个方法,查询empInfo信息, 其中empAnnexInfos为其他类引用对象
var sendData = { ‘userName‘ : userName};//数据 josn格式数据 var url = "user!searchEmpInfo";//地址 $.ajax({//注意写法是josn格式的 推荐使用ajax 原因是速度快 url : url,//地址 data : sendData,//参数 type : ‘post‘,//设置提交类型 success : function(data) {//请求成功的回调函数 var emps=eval(data); $(emps).each(function (i, emp) { var empAnn=eval(emp.empAnnexInfos); $(empAnn).each(function (i, ema){ var img=‘<img src="‘+ema.empHead+‘" width="120" height="200"/>‘; $(‘#empInfo .images‘).html(img); }); var empInfo=‘姓 名:‘+emp.empName+‘<hr/>联系电话:‘+emp.empMobilePhone+‘<hr/>联系邮箱:‘+emp.empEmail+‘<hr/>家庭住址:‘+emp.empAddress+‘<hr/>目前薪资:‘+emp.empSalary; empInfo+=‘<hr/>入职时间‘+emp.emTime; $(‘#empInfo .einfo‘).html(empInfo); }); }
});
action方法:
public void searchEmpInfo() throws Exception{ String name=this.getUserName().trim(); this.setEmpInfo(emd.getEmpInfoByEmpNum(name)); if(empInfo.getEmpAnnexInfos()==null){ System.out.println("annexinfo is null"); } PrintWriter out=this.getResponse().getWriter(); JsonConfig cfg = new JsonConfig(); JSONArray jsonList=JSONArray.fromObject(empInfo,cfg);
System.out.println(jsonList.toString());//输出josn数据字符串 out.print(jsonList.toString()); }
如果使用PrintWriter就不需要配置struts.xml
最终运行结果,依然是内存溢出,当我吧控制台输出的josn字符串复制到sublimeText中查看时, 出现了一个吓人的结果:
密密麻麻N长一片,仔细看,这些乱七八糟的数据,就是Josn..我想这就是内存溢出的真正原因了,虽然employee对象本身并不大,而在EmployeeInfo.java中却引用了其他7个实体类的引用,7个实体类同样引用了EmployeeInfo对象,这下纠结了...毫无疑问直接传递员工对象Josn陷入死循环就是内存溢出的根本原因所在...
网上查了一下能将josn去掉关联的方法:
参考:http://www.2cto.com/kf/201303/198961.html的方法
修改上面的action方法:
public void searchEmpInfo() throws Exception{ String name=this.getUserName().trim(); this.setEmpInfo(emd.getEmpInfoByEmpNum(name)); if(empInfo.getEmpAnnexInfos()==null){ System.out.println("annexinfo is null"); } PrintWriter out=this.getResponse().getWriter(); JsonConfig cfg = new JsonConfig(); cfg.setExcludes(new String[]{"employeeInfo","borders","workOverTimes","askForLeaveEaas","compacts","goOnErrandses","empBoons","udops","replacingPosts","transferEmps","rewardPunishments","timeBooks","post"}); JSONArray jsonList=JSONArray.fromObject(empInfo,cfg);
System.out.println(jsonList.toString());//输出josn数据字符串
out.print(jsonList.toString());
}
这一次查看josn字符串,过滤成功,如图:
页面运行效果:
内存溢出终于解决.....
该好好睡觉了....