使用 iText:java.lang.OutOfMemoryError:请求的数组大小超出 VM 限制

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26256061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:35:17  来源:igfitidea点击:

Using iText: java.lang.OutOfMemoryError: Requested array size exceeds VM limit

javapdfout-of-memoryitext

提问by Bo ?berg

I'vew been using iText 4.2.1 and java 1.6 to generate PDF-files. My task is to add two fields having some random content using a template pdf. It works fine even with an 1GB large PDF. But now the environment demands java 7 and I run into this Out of memory-problem. I'v upgraded the iText to 5.5.3, but still the same issue. The code is trivial:

我一直在使用 iText 4.2.1 和 java 1.6 来生成 PDF 文件。我的任务是使用模板 pdf 添加具有一些随机内容的两个字段。即使使用 1GB 的大 PDF,它也能正常工作。但是现在环境需要 java 7,我遇到了内存不足的问题。我已经将 iText 升级到 5.5.3,但仍然是同样的问题。代码很简单:

public final class PdfHelper
{
    public static void randomizePDFStream(InputStream in, OutputStream out)
    {
        try
        {
            PdfReader ReadInputPDF;
            ReadInputPDF = new PdfReader(in);
-> crash            PdfStamper stamper = new PdfStamper(ReadInputPDF, out);
            HashMap<String, String> hMap = ReadInputPDF.getInfo();
            hMap.put("Title", "RANDOM PDF TITLE: " + System.nanoTime() + ", " + System.currentTimeMillis());
            hMap.put("Subject", "RANDOM PDF SUBJECT: " + System.currentTimeMillis() + ", " + System.nanoTime());
            stamper.setMoreInfo(hMap);
            stamper.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

This gives the following stack dump when using a 1GB large pdf file :

使用 1GB 大 pdf 文件时,这会提供以下堆栈转储:

Caught: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
        at java_util_concurrent_Future$get.call(Unknown Source)
        at Main.awaitCompletion(Main.groovy:222)
        at Main$awaitCompletion.callCurrent(Unknown Source)
        at Main.run(Main.groovy:113)
Caused by: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
        at com.itextpdf.text.io.StreamUtil.inputStreamToArray(StreamUtil.java:74)
        at com.itextpdf.text.io.RandomAccessSourceFactory.createSource(RandomAccessSourceFactory.java:146)
        at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:351)
        at com.itextpdf.text.pdf.PdfReader.<init>(PdfReader.java:371)
        at PdfHelper.randomizePDFStream(PdfHelper.java:65)

This is called from a groovy script with this basic code:

这是从带有以下基本代码的 groovy 脚本中调用的:

mPDFFiles[i] = new java.io.File(getTempDirectory(), String.format("temp_file_%s_%s.pdf", System.nanoTime(), i));
mPDFFiles[i].createNewFile();

input = new BufferedInputStream(new FileInputStream(mTemplateFiles[i]));
output = new BufferedOutputStream(new FileOutputStream(mPDFFiles[i]));

long start=System.currentTimeMillis();
PdfHelper.randomizePDFStream(input, output);
output.flush();
println "Conversion time: " + (System.currentTimeMillis()-start) + " ms."

Anyone having an idea how to get this to work?

任何人都知道如何让它发挥作用?

回答by Nirav Prajapati

You can use command-line parameters to increase the amount of memory available to Java. Here is an example of the command-line parameters that I use - you should change the numbers as appropriate for your needs and system memory capacity:

您可以使用命令行参数来增加 Java 可用的内存量。这是我使用的命令行参数的示例 - 您应该根据需要和系统内存容量更改数字:

Xms256m -Xmx1024m -XX:+DisableExplicitGC -Dcom.sun.management.jmxremote
-XX:PermSize=256m -XX:MaxPermSize=512m

回答by Johannes

Some options of what you could do:

你可以做的一些选择:

  1. Tell the JVM (which executes your Groovy code and the PdfStamper inside) to allow use of more memory (-Xmxetc. Consult your JVM documentation).
  2. Find an implementation that does not require to load the complete PDF into memory (at least not at once).
  1. 告诉 JVM(它执行您的 Groovy 代码和内部的 PdfStamper)以允许使用更多内存(-Xmx等。请参阅您的 JVM 文档)。
  2. 找到一个不需要将完整的 PDF 加载到内存中的实现(至少不是一次)。

(I'm wondering why the implementation of iText and its PdfStamper is not efficient enough to accomplish your task without using a huge amount of memory...)

(我想知道为什么 iText 及其 PdfStamper 的实现效率不足以在不使用大量内存的情况下完成您的任务......)

回答by Lonzak

The error says "Requested array size exceeds VM limit" - the maximum size of an array is around 2GB (Integer.MAX_VALUE). The question is what VM are you running? 32 GB or 64 GB? You may try the following options (64 Bit VM):

错误显示“请求的数组大小超出 VM 限制” - 数组的最大大小约为 2GB (Integer.MAX_VALUE)。问题是你在运行什么虚拟机?32 GB 还是 64 GB?您可以尝试以下选项(64 位虚拟机):

-XX:+UseCompressedOops

-XX:+UseCompressedOops