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