git00ll
V2EX  ›  问与答

poi 读取 excel 内存溢出

  •  1
     
  •   git00ll · Jul 31, 2021 · 1800 views
    This topic created in 1747 days ago, the information mentioned may be changed or developed.

    现象

    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) 方法内

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

    前几天刚遇到这个问题。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1332 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 50ms · UTC 17:20 · PVG 01:20 · LAX 10:20 · JFK 13:20
    ♥ Do have faith in what you're doing.