【问题标题】:JVM crashes at ZipFile.getNextEntry() - part of POI's BigGridDemoJVM 在 ZipFile.getNextEntry() 崩溃 - POI 的 BigGridDemo 的一部分
【发布时间】:2011-08-23 14:51:07
【问题描述】:

我有一个 Java 应用程序来生成 Excel 工作表。我是根据 Apache POI 的 BigGridDemo Example 来生成 Excel(xlsx) 的。

这个想法是

  1. 创建模板工作簿、创建工作表和全局对象,例如单元格样式、数字格式等。
  2. 创建一个在文本文件中流式传输数据的应用程序
  3. 用生成的数据替换模板中的工作表

在 Linux 中,在第 3 步中,JVM 因此信息而崩溃

# A fatal error has been detected by the Java Runtime Environment:
#  SIGSEGV (0xb) at pc=0x000000307a772c44, pid=11781, tid=1088649568
#
# JRE version: 6.0_24-b07
# Java VM: Java HotSpot(TM) 64-Bit Server VM (19.1-b02 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libc.so.6+0x72c44]  memcpy+0x34

hs_err_pid 文件有这个 -

C  [libc.so.6+0x72c44]  memcpy+0x34

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  java.util.zip.ZipFile.getNextEntry(JI)J+0
j  java.util.zip.ZipFile.access$400(JI)J+2
j  java.util.zip.ZipFile$2.nextElement()Ljava/util/zip/ZipEntry;+54
j  java.util.zip.ZipFile$2.nextElement()Ljava/lang/Object;+1

当模板工作簿作为 zip 文件读取时,似乎会发生这种情况。这是执行此操作的代码。

ZipFile zip = new ZipFile(zipfile);
ZipOutputStream zos = new ZipOutputStream(out);

Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
while (en.hasMoreElements()) {
    ZipEntry ze = en.nextElement();
    if(!ze.getName().equals(entry)){
        zos.putNextEntry(new ZipEntry(ze.getName()));
        InputStream is = zip.getInputStream(ze);
        copyStream(is, zos);
        is.close();
    }
}

如何避免这种崩溃?

【问题讨论】:

  • 您是否添加了 -xMx 参数来增加 JVM 的大小?您是否正在运行可能设置该参数的东西(Tomcat、Jetty、JBoss)?当你这样做时,Linux 端的系统内存是什么样的?你的电量不足吗?
  • 是的。当我也尝试使用 -Xmx1024m 和 2048 时,就会出现这种情况。我没有使用应用程序服务器运行。就像一个独立的 java 应用程序一样。机器内存充足(>15GB)。
  • 我建议您从 BigGridDemo 切换到新的 SXSSF。它可以让您完成 BigGridDemo 所做的低内存写入,但使用更简单的 API
  • @Gagravarr,SXSSF 运行良好。谢谢。

标签: java crash zip apache-poi


【解决方案1】:

鉴于您遇到的崩溃类型,您似乎正在读取和写入同一个 zip 文件。

wrote up why this happens in another answer,但对于您的用例,您应该在遍历输入 zip 文件时写入不同的输出 zip 文件。

【讨论】:

    【解决方案2】:

    如果您告诉 JVM 使用 1GB、2GB 等,并且系统没有那么多可用内存,JVM 将在 linux(可能是其他平台)上崩溃。当 JVM 中的程序尝试分配比 JVM 上的最大内存设置更多的内存时,会导致 OutOfMemoryException 并且 JVM 不会崩溃。我会检查并确保您的系统上没有其他程序占用的内存比您意识到的要多。您还可以检查来自 JVM 的堆转储。当 JVM 崩溃时,它会写出一份报告,告诉您有关机器在崩溃时的状态的更多信息,例如正在使用多少系统内存。

    1GB 是一个巨大的内存量。我的 IDE 没有那么多内存运行。您可能需要查看您在 jconsole 或分析器中所做的事情,看看您自己是否正在消耗内存。我知道 POI 会占用大量内存,但您需要想办法将其拉回。

    【讨论】:

    • 我添加了 1 GB 和 2 GB 只是为了确保 java 获得足够的内存。它看起来不像 OutOfMemory。这是崩溃期间的内存报告 - Heap PSYoungGen total 17984K used 10492K, eden space 15424K 52% used, from space 2560K 53% used, to space 2560K 0% used。也只有 10 行要生成。使用这种方法的重点是减少 POI 的内存消耗。
    • 崩溃发生在 memcpy 内部,因此 C 代码正在分配内存。通常这意味着它正在尝试增加堆并且 JVM 进程低于 -Xmx 设置的 1GB 限制。但是,如果您的机器(不是 JVM)内存不足,则 memcpy 将失败,并且 JVM 将使您崩溃。如果您查看程序的内存使用情况,在这些情况下它看起来很正常。如果你的 linux 机器内存不足,它只能使用 25M 崩溃。
    • 我还看到卡在机器中的内存不匹配时崩溃。添加 2GB 和 1GB 模块的混合。或者有时内存时间是混合的,这可能会导致崩溃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    • 2022-11-01
    • 2014-10-13
    相关资源
    最近更新 更多