最近做一个项目,环境是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字符串,过滤成功,如图:

 

页面运行效果:

 

内存溢出终于解决.....

该好好睡觉了....