查询导致内存溢出优化

报错信息

org.springframework.web.util.NestedServletException: 
Handler dispatch failed; nested exception is java.lang.OutOfMemoryError:Java heap space

出现原因

        //查询了大量的userId  
        List<Long> loanUserIds = bidMapper.findLoanUserIds();
        //将userId作为参数继续查询
        List<UserDistribute> loanUserDistributes = usersMapper.findUserDistribute(loanUserIds, loanUserIds.size());
    <select id="findUserDistribute" resultType="com.mmtvip.mainhomeapi.vo.datadisclosure.UserDistribute">
        SELECT
            tap.`NAME` AS `province`,
            t.cou/#{size} AS `ratio`
        FROM
            (
                SELECT
                    count(1) cou,
                    province_id province
                FROM
                    t_dict_ad_citys tdac,
                    (
                        SELECT city_id ci
                        FROM t_users tu
                        WHERE tu.id IN
                            <foreach collection="userIds" item="id" separator="," open="(" close=")" >
                                #{id}
                            </foreach>
                        AND tu.city_id != 0
                    ) tc
                WHERE tc.ci = tdac.id
                GROUP BY province_id
                ORDER BY cou DESC
            ) t
        LEFT JOIN t_dict_ad_provinces tap ON 	t.province = tap.id
        ORDER BY t.cou DESC LIMIT 10
    </select>

解决方案

//将结果在sql中直接查出
List<UserDistribute> loanUserDistributes = usersMapper.findUserDistribute();
    <select id="findUserDistribute" resultType="com.mmtvip.mainhomeapi.vo.datadisclosure.UserDistribute">
        SELECT
            tap.`NAME` AS `province`,
            t.cou/
                    (SELECT COUNT(DISTINCT user_id) FROM t_bids WHERE `STATUS` IN (4, 5, 14))
                    AS `ratio`
        FROM
            (
                SELECT
                    count(1) cou,
                    province_id province
                FROM
                    t_dict_ad_citys tdac,
                    (
                        SELECT city_id ci
                        FROM t_users tu
                        WHERE tu.id IN
                              (SELECT DISTINCT user_id FROM t_bids WHERE `STATUS` IN (4, 5, 14))
                        AND tu.city_id != 0
                    ) tc
                WHERE tc.ci = tdac.id
                GROUP BY province_id
                ORDER BY cou DESC
            ) t
        LEFT JOIN t_dict_ad_provinces tap ON t.province = tap.id
        ORDER BY t.cou DESC LIMIT 10
    </select>

 

### Java处理大量数据时内存溢出的解决方案 当Java程序在查询或处理大量数据时遇到内存溢出(`OutOfMemoryError`),可以通过多种方式优化和调整来解决问题。以下是几种常见的方法: #### 1. 增加JVM堆内存大小 通过设置JVM参数增加可用堆内存是一种简单有效的方法。可以使用以下命令行选项来增大堆空间: ```bash -Xms<初始堆大小> -Xmx<最大堆大小> ``` 例如,将最小堆设为512MB,最大堆设为4GB: ```bash java -Xms512m -Xmx4g YourApplication ``` 这种方法适用于硬件资源充足的情况[^1]。 #### 2. 使用分页机制加载数据 如果一次性加载的数据量过大,可以考虑采用分页的方式逐步读取数据。这种方式能够显著减少单次操作所需的内存占用。例如,在数据库查询中实现分页逻辑: ```sql SELECT * FROM table_name LIMIT start_index, page_size; ``` 配合Java代码逐页获取并处理数据,从而降低内存压力[^2]。 #### 3. 利用流式处理技术 对于大数据文件(如Excel或其他格式),推荐使用流式API进行逐行解析而非一次性载入整个文档到内存中。Apache POI库提供了SXSSF模式专门用于高效处理大规模Excel表格: ```java import org.apache.poi.xssf.streaming.SXSSFWorkbook; public class LargeDataHandler { public static void main(String[] args) throws Exception { SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 缓存100行后刷新磁盘 try (workbook; FileOutputStream out = new FileOutputStream("large_file.xlsx")) { for (int i = 0; i < 100000; i++) { // 创建大量行 var sheet = workbook.getSheetAt(0); if (sheet == null) { sheet = workbook.createSheet(); } var row = sheet.createRow(i); row.createCell(0).setCellValue("Cell " + i); } workbook.write(out); } finally { workbook.dispose(); // 清理临时文件 } } } ``` 上述代码展示了如何利用SXSSF避免全量加载造成的内存消耗问题。 #### 4. 数据结构优化与对象池复用 合理设计数据模型以及重用已存在的实例也可以缓解部分场景下的OOM风险。比如引入软/弱引用管理不再使用的对象以便GC及时回收;或者构建自定义的对象池以控制生命周期内的分配频率等策略均有助于提升性能表现。 #### 5. 启动垃圾收集器调优 适当配置G1 GC或者其他现代算法可能带来更好的吞吐率体验。具体做法包括但不限于指定目标暂停时间(-XX:MaxGCPauseMillis),预估新生代比例(-XX:NewRatio=N),启用并发标记清除功能等等。 --- ### 总结 综上所述,针对Java应用运行期间因海量数据引发的内存不足状况,可采取扩展物理资源配置、改进业务流程架构、选用合适的技术框架等多种手段加以应对。每种措施都有其适用范围及局限性,实际开发过程中需综合考量项目需求和技术条件做出最佳抉择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值