poi 读取 excel 内存溢出

2021-07-31 21:14:29 +08:00
 git00ll

现象

excel 文件,约 50M 。java 堆内存给到 512m,采用流式方式读取,出现 oom,Java heap space 。

问题

话说流式读取不应该很省内存的吗,为啥 50M 的都读不了。

源码

跟踪 poi 代码 发现在

org.apache.commons.compress.archivers.zip.ZipArchiveInputStream#getNextZipEntry

方法 293 行 new ZipLong(lfhBuf, off);获取到的长度, 该长度是从文件头部获取的长度,不太理解这个获取到的长度是由什么决定的。

在方法 org.apache.poi.util.IOUtils#toByteArray(java.io.InputStream, int)中进行读取数据时,堆内存爆了,暂时没找到限制该大小的办法,此大小应该和文件本身的大小有关。

补充

问题发生在 OPCPackage.open(stream) 方法内

1367 次点击
所在节点    问与答
8 条回复
hefish
2021-07-31 21:21:38 +08:00
把 java 的内存调大啊。
git00ll
2021-07-31 21:40:19 +08:00
首先 xlsx 文件本身是一个压缩包,即使是 event 模式,poi 也需要将压缩包内的文件全部加载在内存里,真实使用时再根据流式方式边解析边向外输出。
也就是说最低需要 xlsx 解压后的文件大小的内存才可以进行解析。
wangsongyan
2021-07-31 21:44:57 +08:00
我记着 easypoi 解决了 oom 问题
git00ll
2021-07-31 21:45:40 +08:00
512m 堆内存是比文件解压后大的,但是其中有一个数组拷贝操作,导致同时会存在两个在内存里,就不够了。
所以内存要比文件解压大两倍。
micean
2021-07-31 21:49:52 +08:00
换 easyexcel 试试,sax 模式能一定程度上解决这个问题
potatowish
2021-07-31 23:31:22 +08:00
easyexcel 已经解决了内存溢出的问题
sagaxu
2021-08-01 01:30:26 +08:00
@git00ll 512M 的堆,实际可用的也就 300M 样子,JVM 自己要消耗一些,GC 腾挪又要消耗掉一些,每个对象还有 16 字节额外开销。假设你要同时存两份,解压后 150M 左右该 OOM 了
blackshadow
2021-08-01 08:16:48 +08:00
github 上找找,我就觉得有实例代码,是利用 poi 的其他接口的,不会 oom,但某些格式的会读不了。

前几天刚遇到这个问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/792910

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX