Java进程CPU占用100%求助:ResultSet转CSV方法疑因排查
排查Java进程CPU占用100%:Apache CSV解析ResultSet的问题分析
你已经精准定位到了问题触发点——注释掉writeResultSetToFile方法后CPU立刻回归正常,这说明这个方法的实现确实存在性能瓶颈。结合你使用的commons-csv-1.5.jar,我来拆解几个核心排查方向和优化建议:
1. ResultSet遍历的性能隐患
首先要怀疑ResultSet的处理方式:如果没有合理配置fetchSize,数据库会一次性把所有结果加载到内存,再加上逐行写入CSV的操作,很容易让CPU持续高负载。
- 给ResultSet设置合适的批量拉取大小,比如
resultSet.setFetchSize(1000)(根据数据量级调整),避免一次性加载百万级数据到内存。 - 检查遍历逻辑:确认你是通过
resultSet.next()正确推进游标,有没有出现无限循环的情况(比如循环条件写错,导致一直重复处理同一行数据)。
2. Apache CSV的使用与配置问题
commons-csv的CSVPrinter如果使用不当,也会消耗大量CPU:
- 字符编码与Writer优化:如果结果集中包含大量非ASCII字符,默认的字符处理可能效率低下。建议显式指定UTF-8编码,并给BufferedWriter设置更大的缓冲区:
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), 32768); // 32KB缓冲区 - 资源管理漏洞:你的代码片段里只声明了
BufferedWriter和CSVPrinter,但没看到关闭逻辑。如果没有在finally块或用try-with-resources自动关闭资源,长期运行会引发资源泄漏,间接拉高CPU。建议重构为:try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), 32768); CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT)) { // 遍历ResultSet并写入CSV的逻辑 while (resultSet.next()) { // 读取列数据并调用csvPrinter.printRecord() } } catch (IOException | SQLException e) { e.printStackTrace(); }
3. 大数据量下的IO瓶颈
如果ResultSet返回的数据量极大,小缓冲区的BufferedWriter会频繁触发磁盘IO,导致CPU一直在等待IO完成的循环中忙碌。扩大缓冲区能减少IO次数,降低CPU负载。
4. 利用线程转储精准定位
你提到有线程转储,这是排查的关键!可以这么分析:
- 用
top -H(Linux)或任务管理器(Windows)找到CPU占用最高的线程ID,转换成十六进制后,在线程转储里找到对应的栈帧。 - 看栈帧是否卡在CSVPrinter的
printRecord、escape等字符处理方法上——如果是,说明字符转义或格式化是CPU消耗的核心点,可以尝试调整CSVFormat的配置(比如关闭不必要的转义规则)。
快速验证方案
- 先给ResultSet设置
fetchSize,并用try-with-resources重构资源管理,测试CPU是否下降。 - 用小数据集测试:如果小数据量下CPU正常,说明是大数据量的处理效率问题,重点优化缓冲区和批量处理逻辑。
- 替换CSV库对比:比如用OpenCSV实现同样的逻辑,看CPU占用是否正常,排除commons-csv版本的固有问题。
内容的提问来源于stack exchange,提问作者John Thomas
相关产品推荐
相关产品推荐

