JVM在ZipFile.getNextEntry()处崩溃 - POI的BigGridDemo的一部分

3
我有一个用Java编写的应用程序,可以生成Excel表格。我是基于Apache POI的BigGridDemo示例来生成Excel(xlsx)文档。

实现的思路如下:

  1. 创建一个模板文档,包括工作表和全局对象例如单元格样式、数字格式等等
  2. 开发一个应用程序,将数据以文本文件的形式流式传输
  3. 使用生成的数据替换模板中的工作表

在Linux系统中,在第三步中,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端的系统内存如何?你的内存是否不足? - chubbsondubs
是的。当我尝试使用-Xmx1024m和2048时出现这种情况。我没有运行应用服务器,只是作为一个独立的Java应用程序运行。机器上有足够的内存(>15GB)。 - kpk
1
我建议您从BigGridDemo切换到新的SXSSF。它将让您执行BigGridDemo所做的低内存写入,但使用更易于使用的API。 - Gagravarr
2个回答

1

0

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

1GB是非常大的内存量。我的IDE不需要那么多内存来运行。您可能需要查看jconsole或分析器中正在执行的操作,以确定是否自己使用了太多内存。我知道POI会耗费大量内存,但您需要找到方法将其降下来。


我增加了1 GB和2 GB的内存,只是为了确保Java获得足够的内存。看起来不像是OutOfMemory。这是崩溃期间的内存报告 - Heap PSYoungGen总共17984K,已使用10492K,伊甸园空间15424K使用了52%,from space 2560K使用了53%,to space 2560K使用了0%。还要生成10行。使用此方法的整个目的是减少POI的内存消耗。 - kpk
崩溃发生在memcpy内部,因此C代码正在分配内存。通常这意味着它正在尝试增加堆,并且JVM进程处于由-Xmx设置的1GB限制以下。但是,如果您的机器(而非JVM)内存不足,则memcpy将失败,并且JVM将崩溃。在这些情况下,如果您查看程序的内存使用情况,它看起来很正常。如果您的Linux框只使用了25M,也可能会崩溃。 - chubbsondubs
我也曾见过由于机器中的内存不匹配而导致的崩溃。例如,添加了2GB和1GB模块的混合内存。或者有时内存时序混合使用也会导致崩溃。 - chubbsondubs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接