Java 创建10000个+;带iText的PDF页面

Java 创建10000个+;带iText的PDF页面,java,pdf,pdf-generation,out-of-memory,itext,Java,Pdf,Pdf Generation,Out Of Memory,Itext,我需要在iText(2.1.7)中生成非常长的PDF,其中页面由Graphics2D绘制。问题是,每个页面需要约2MB的内存,因此创建一个10000页的pdf需要约20GB的内存。是否有可能在硬盘上每100页刷新一部分com.lowagie.Text.Document?我已经尝试过PdfWriter.flush(),但没有帮助 这里有一个小代码。使用-Xmx200m结果运行它OutOfMemoryError import java.awt.Color; import java.awt.Graph

我需要在iText(2.1.7)中生成非常长的PDF,其中页面由
Graphics2D
绘制。问题是,每个页面需要约2MB的内存,因此创建一个10000页的pdf需要约20GB的内存。是否有可能在硬盘上每100页刷新一部分
com.lowagie.Text.Document
?我已经尝试过PdfWriter.flush(),但没有帮助

这里有一个小代码。使用-Xmx200m结果运行它
OutOfMemoryError

import java.awt.Color;
import java.awt.Graphics2D;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.lowagie.text.Document;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfTemplate;
import com.lowagie.text.pdf.PdfWriter;


public class Main {

    static String FILENAME = "/home/username/tmp/out.pdf";

    public static void main(String[] args) {
        try {
            System.out.println(printMem());

            Rectangle rectPage = new Rectangle(0, 0, 210, 297);

            FileOutputStream fos = new FileOutputStream(new File(FILENAME));
            Document d = new Document(rectPage, 0, 0, 0, 0);

            PdfWriter writer = PdfWriter.getInstance(d, fos);


            d.open();




            int pageNo = 200;

            for (int i = 0; i < pageNo; i++) {
                d.newPage();

                PdfContentByte cb;
                PdfTemplate tp;
                Graphics2D g2;


                cb = writer.getDirectContent();

                tp = cb.createTemplate(rectPage.getWidth(),
                        rectPage.getHeight());
                g2 = tp.createGraphicsShapes(rectPage.getWidth(),
                        rectPage.getHeight());

                paintRand(g2);

                g2.dispose();
                cb.addTemplate(tp, 0, 0);

                System.out.println(i + ") " + printMem());
                writer.flush();


            }


            d.close();

            System.out.println(printMem());
            System.out.println("done");






        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
        } catch (OutOfMemoryError mem) {
            System.err.println("OUT OF MEMORY!!!!!!! " + printMem());
            mem.printStackTrace();
        }
    }






    private static String printMem() {
        final long usedMem = Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory();
        String ram = "RAM: " + (usedMem / 1024 / 1024) + "MB / "
                + (Runtime.getRuntime().totalMemory() / 1024 / 1024) + "MB";
        if (Runtime.getRuntime().maxMemory() != Long.MAX_VALUE) {
            ram += " (max limit: " + Runtime.getRuntime().maxMemory() / 1024
                    / 1024 + "MB)";
        } else {
            ram += " (no max limit)";
        }

        return ram;
    }

    private static Random rand = new Random();

    private static List<Color> colors = new ArrayList<Color>()
    {
        {
            add(new Color(33, 33, 33));
            add(new Color(33, 33, 36));
            add(new Color(33, 33, 44));
            add(new Color(33, 33, 38));
        }
    };

    private static void paintRand(Graphics2D g2) {
        int count = 10000;

        for (int i = 0; i < count; i++) {
            g2.setColor(colors.get(rand.nextInt(colors.size())));
            g2.fillOval(rand.nextInt(210), rand.nextInt(210), rand.nextInt(55), rand.nextInt(55));
        }
    }
}

有没有像BufferedWriter那样在peaces中编写文档的选项?

很难理解为什么仍然使用iText 2.1.7。这个问题的答案是“不!”所以请成为一项运动并升级

至于你的问题:你应该区分不同的问题

请检查以下问题的答案:

您会注意到,iText 2.1.7不能用于创建大于2GB的文件。知道每个页面需要2MB,并且您希望有10K个页面,您应该意识到您不能使用iText 2.1.7来实现您的目标

您甚至尝试创建大于PDF 1.4固有限制的文件,因此您必须确保使用压缩的交叉引用表,这是PDF 1.5中引入的功能

另外:如果您已经阅读了文档,您应该意识到,只要页面准备就绪,iText就会将每个页面的内容刷新到
OutputStream
。因此,您的问题“是否有可能在硬盘上刷新
文档
每~100页的一部分?”很奇怪

您对问题的诊断是错误的:您正在创建大量的
PdfTemplate
对象,并将它们保存在内存中!您应该使用该方法写入保存在
PdfWriter
内存中的所有
tp
实例。这将释放大量内存

但是在你这么做之前:请做正确的事情并升级

117) RAM: 239MB / 271MB (max limit: 271MB)
118) RAM: 246MB / 271MB (max limit: 271MB)
119) RAM: 244MB / 271MB (max limit: 271MB)
120) RAM: 245MB / 271MB (max limit: 271MB)
121) RAM: 247MB / 271MB (max limit: 271MB)
OUT OF MEMORY!!!!!!! RAM: 242MB / 271MB (max limit: 271MB)
java.lang.OutOfMemoryError: Java heap space
at com.lowagie.text.pdf.ByteBuffer.append_i(Unknown Source)
at com.lowagie.text.pdf.ByteBuffer.append(Unknown Source)
at com.lowagie.text.pdf.ByteBuffer.formatDouble(Unknown Source)
at com.lowagie.text.pdf.ByteBuffer.append(Unknown Source)
at com.lowagie.text.pdf.ByteBuffer.append(Unknown Source)
at com.lowagie.text.pdf.PdfContentByte.HelperRGB(Unknown Source)
at com.lowagie.text.pdf.PdfContentByte.setRGBColorFill(Unknown Source)
at com.lowagie.text.pdf.PdfContentByte.setColorFill(Unknown Source)
at com.lowagie.text.pdf.PdfGraphics2D.setPaint(Unknown Source)
at com.lowagie.text.pdf.PdfGraphics2D.setFillPaint(Unknown Source)
at com.lowagie.text.pdf.PdfGraphics2D.followPath(Unknown Source)
at com.lowagie.text.pdf.PdfGraphics2D.fill(Unknown Source)
at com.lowagie.text.pdf.PdfGraphics2D.fillOval(Unknown Source)
at Main.paintRand(Main.java:121)
at Main.main(Main.java:54)