You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建JSON对象列表调用toJSONString()时Java堆内存溢出求助

list.toJSONString()触发Java堆内存溢出的解决方法

问题代码

String query1 = "select * from booking where id='"+ids+"'";

rs = stmt.executeQuery(query1);

JSONObject obj = new JSONObject();
while(rs.next())
{
    
    String passengerName = rs.getString("passengerName");
    String passengerPhone = rs.getString("passengerPhone");
    String emergencyPhone = rs.getString("emergencyPhone");
    String trip = rs.getString("trip");
    String destination = rs.getString("destination");
    String seatNumber = rs.getString("seatNumber");
    String cad = rs.getString("idNumber");
    obj.put("passengerName", passengerName);
    obj.put("passengerPhone", passengerPhone);
    obj.put("emergencyPhone", emergencyPhone);
    obj.put("trip", trip);
    obj.put("destination", destination);
    obj.put("seatNumber", seatNumber);
    obj.put("cad", cad);
    list.add(obj);
}

out.print(list.toJSONString());
out.flush();

报错信息

2022年7月23日 11:44:00.326 严重 [http-nio-81-exec-10] org.apache.catalina.core.StandardWrapperValve.invoke 上下文路径为[/ctracker]的Servlet[jsp]的service()方法抛出异常[处理[calData.jsp]时在第282行发生异常]
第282行代码为:

out.print(list.toJSONString());

根因:java.lang.OutOfMemoryError: Java堆内存空间不足

问题分析与修复方案

1. 代码逻辑错误:重复复用同一个JSONObject对象

原代码将JSONObject obj = new JSONObject();放在循环外部,每次循环仅修改该对象的属性值再添加到列表中,导致列表中所有元素均指向同一个对象引用——这不仅会导致最终列表中所有元素都是最后一条记录的值,还会在序列化时产生额外内存消耗。
修复:将JSONObject实例化代码移至循环内部,每次迭代创建新对象:

while(rs.next())
{
    JSONObject obj = new JSONObject(); // 移至循环内,每次创建新对象
    String passengerName = rs.getString("passengerName");
    String passengerPhone = rs.getString("passengerPhone");
    String emergencyPhone = rs.getString("emergencyPhone");
    String trip = rs.getString("trip");
    String destination = rs.getString("destination");
    String seatNumber = rs.getString("seatNumber");
    String cad = rs.getString("idNumber");
    obj.put("passengerName", passengerName);
    obj.put("passengerPhone", passengerPhone);
    obj.put("emergencyPhone", emergencyPhone);
    obj.put("trip", trip);
    obj.put("destination", destination);
    obj.put("seatNumber", seatNumber);
    obj.put("cad", cad);
    list.add(obj);
}

2. 大数据量一次性加载导致堆内存耗尽

若查询返回的记录数过多,将所有数据加载到列表后再一次性序列化,会占用大量堆内存触发溢出。
解决方法:

  • 分页查询:修改SQL添加分页条件(不同数据库语法不同,如MySQL用LIMIT offset, size),避免一次性加载全量数据。
  • 流式序列化输出:不将所有数据存入列表,边读取ResultSet边输出JSON,减少内存占用:
    out.print("[");
    boolean isFirst = true;
    while(rs.next())
    {
        if(!isFirst){
            out.print(",");
        }
        isFirst = false;
        JSONObject obj = new JSONObject();
        // 赋值属性
        obj.put("passengerName", rs.getString("passengerName"));
        obj.put("passengerPhone", rs.getString("passengerPhone"));
        obj.put("emergencyPhone", rs.getString("emergencyPhone"));
        obj.put("trip", rs.getString("trip"));
        obj.put("destination", rs.getString("destination"));
        obj.put("seatNumber", rs.getString("seatNumber"));
        obj.put("cad", rs.getString("idNumber"));
        out.print(obj.toJSONString());
        out.flush(); // 实时输出,释放内存
    }
    out.print("]");
    out.flush();
    
  • 调整JVM堆内存:临时缓解方案,修改Tomcat启动参数增大堆内存,例如在catalina.sh(Linux)或catalina.bat(Windows)中添加:
    -Xms512m -Xmx1024m
    
    其中-Xms为初始堆内存,-Xmx为最大堆内存,可根据服务器配置调整。

3. 修复SQL注入漏洞

原代码直接拼接字符串生成SQL,存在严重SQL注入风险,且若参数异常可能返回大量数据加重内存负担。
修复:使用PreparedStatement预编译SQL:

String query1 = "select * from booking where id=?";
PreparedStatement pstmt = conn.prepareStatement(query1);
pstmt.setString(1, ids);
rs = pstmt.executeQuery();

内容的提问来源于stack exchange,提问作者maxwell Owusu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:27:23