比较两个Excel文件时触发java.lang.OutOfMemoryError: GC overhead limit exceeded问题求助
解决Excel比较时的GC Overhead Limit Exceeded异常
嘿,这个GC开销超限的错误我之前处理大Excel文件时也碰到过,特别闹心!咱们一步步来搞定它:
先搞懂为啥会出这个错
java.lang.OutOfMemoryError: GC overhead limit exceeded这个错误说白了就是:JVM花了超过98%的时间在垃圾回收上,但真正回收回来的内存却不到2%,相当于一直在做无用功,系统干脆直接抛出错误终止程序了。大多是因为内存不够用,或者咱们的代码内存使用效率太低导致的。
具体解决办法
1. 先给JVM加内存(最直接的办法)
处理大Excel文件时,默认的JVM内存肯定不够用,直接给它分配更多内存就行。你可以在启动程序的时候加上这些参数:
-Xms2g:设置初始堆内存为2GB(根据你机器的内存调整,比如4g、8g都没问题,只要不超过物理内存的一半就行)-Xmx8g:设置最大堆内存为8GB-XX:+UseG1GC:用G1垃圾收集器,它对大内存的处理更高效,能减少GC停顿的时间
举个例子,如果你用命令行启动程序,命令大概是这样:
java -Xms2g -Xmx8g -XX:+UseG1GC YourMainClass
要是用IDE(比如IntelliJ IDEA),直接在Run Configuration的VM options里添加这些参数就行,亲测有效!
2. 别把整个Excel都读到内存里(关键优化)
你现在的代码是把两个工作表全读到ArrayList<ArrayList<String>>里,这种方式对大文件来说简直是内存杀手!换成流式读取的方式,比如用Apache POI的SXSSF(针对XLSX格式)或者事件模型:
- SXSSF会把大部分数据写到磁盘的临时文件里,只保留少量行在内存中,内存占用瞬间降下来
- 如果是旧版的XLS格式,就用HSSF的事件模型来逐行解析
给你个SXSSF读取的代码思路参考:
// 只保留100行在内存,其余写到磁盘 SXSSFWorkbook workbook = new SXSSFWorkbook(100); Sheet sheet = workbook.getSheetAt(0); for (Row row : sheet) { // 逐行处理数据,不用一次性存下整个表 // 处理完就可以把当前行的引用置为null,方便GC回收 } // 记得处理完后清理临时文件,避免磁盘占用 workbook.dispose();
3. 优化代码里的内存细节
- 别用
ArrayList<ArrayList<String>>这种嵌套集合了,换成自定义的Java对象或者数组,减少不必要的对象开销 - 处理完的数据及时设为
null,让GC能尽快把这些内存收回去 - 如果Excel行数特别多,可以分批次比较:比如每次读1000行,比较完就清理这部分内存,再读下一批,不用一次性加载所有数据
4. 检查有没有内存泄漏
有时候不是内存不够,而是代码里有内存泄漏——比如某个静态集合一直抱着大量数据不松手,或者某个对象的引用没释放。可以用VisualVM这种工具来分析内存使用情况,找出内存泄漏的地方,针对性修复。
内容的提问来源于stack exchange,提问作者Tan90
相关产品推荐
相关产品推荐

