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

如何用BufferedReader读取大型CSV至内存?内存溢出问题求助

问题分析与解决

1. JVM参数未生效的核心原因

你犯了两个关键错误:

  • 把JVM堆参数写到了IntelliJ的程序参数框里,正确的位置是「Run/Debug Configurations」中的「VM options」栏,程序参数是传给main方法的参数,不会被JVM解析。
  • 参数格式错误:-Xms=20G里的等号是多余的,正确写法是-Xms20G -Xmx20G。
    这两个问题导致你的堆内存配置完全没生效,程序一直使用默认堆大小运行,所以改2M和20G结果一致。

2. 10M行就OOM的内存开销解析

原始文件仅1G,但内存中存储的对象开销远大于原始字节:

  • 每个String包含对象头(约16字节)、char数组(每个char占2字节)、偏移量和长度字段,短字符串的额外占比极高。
  • 每个String[]数组有对象头+元素引用(64位JVM下每个引用8字节),16列的数组仅引用就占128字节。
  • ArrayList的扩容机制会预留1.5倍的空间,进一步增加内存占用。
    10M行×16列的组合,加上这些额外开销,很容易撑爆默认堆(通常几百MB)。

3. 解决方法

第一步:正确配置JVM参数

打开IntelliJ的「Run/Debug Configurations」→ 选中你的运行配置 → 在「VM options」输入框填入:

-Xms20G -Xmx20G

20G堆内存足够容纳16M行的数据集。

第二步:优化内存占用(可选)

如果想进一步降低内存压力,或者修正手动解析CSV的潜在问题(比如字段含逗号时split会出错),可以尝试:

  • 用CSV专用解析库:比如OpenCSV,它的解析逻辑更高效,还能处理CSV格式的特殊场景,示例代码:
List<String[]> res = new ArrayList<>();
CSVReader reader = new CSVReader(new InputStreamReader(s3.getObject(s3BucketName, path).getObjectContent()));
String[] nextLine;
while ((nextLine = reader.readNext()) != null) {
    res.add(nextLine);
}
reader.close();
  • 转存为原始类型数组:如果字段是数字类型,直接解析为int/double存入对应数组,彻底避免String的额外开销。
  • 使用内存高效集合:比如Eclipse Collections的ObjectArrayList,比JDK原生ArrayList节省约20%的内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 14:52:22