V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
git00ll
V2EX  ›  问与答

poi 读取 excel 内存溢出

  •  1
     
  •   git00ll · 125 天前 · 725 次点击
    这是一个创建于 125 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现象

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

    前几天刚遇到这个问题。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2217 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 02:41 · PVG 10:41 · LAX 18:41 · JFK 21:41
    ♥ Do have faith in what you're doing.