最近做一個項目,環境是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字符串,過濾成功,如圖:
頁面運行效果:
內存溢出終於解決.....
該好好睡覺了....