下载PDF文件时从itext获取Java堆空间错误

时间:2016-04-18 06:37:02

标签: java out-of-memory itext

当我们尝试导出为PDF时,我们正面临Java堆空间错误。下面是堆栈跟踪错误

SEVERE: Servlet.service() for servlet jsp threw exception
java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.<init>(HashMap.java:203)
    at com.lowagie.text.pdf.PdfChunk.<init>(Unknown Source)
    at com.lowagie.text.pdf.PdfChunk.split(Unknown Source)
    at com.lowagie.text.pdf.PdfLine.add(Unknown Source)
    at com.lowagie.text.pdf.PdfCell.<init>(Unknown Source)
    at com.lowagie.text.pdf.PdfTable.updateRowAdditionsInternal(Unknown Source)
    at com.lowagie.text.pdf.PdfTable.<init>(Unknown Source)
    at com.lowagie.text.pdf.PdfDocument.addPdfTable(Unknown Source)
    at com.lowagie.text.pdf.PdfDocument.add(Unknown Source)
    at com.lowagie.text.Document.add(Unknown Source)

We are using itext-1.4.4.jar to Export PDF file. There are 30 columns and around 20000 rows. Also we have tried with com.lowagie.text-2.1.7.jar, there also same issue.

Below find the configuration details,

RAM : 8GB
Heap Size : -Xms256m -Xmx1024m -XX:PermSize=64m -XX:MaxPermSize=512m

下面找到将返回字节数组的示例代码段。在将表添加到文档时,我们从itext pdf获得Java堆空间错误。

**Sample Code snippet:**

public static byte[] convertToPdf(ResultSet argResultSet,String argReportName) throws Exception {


ResultSetMetaData metaData = null;
ByteArrayOutputStream outputStream = null;
Document document = null;
byte[] byteArray = null;
try {
    metaData = argResultSet.getMetaData();
    int columnCount = metaData.getColumnCount();

    outputStream = new ByteArrayOutputStream();
    document = new Document(PageSize.A4, 25, 25, 25, 25);
    PdfWriter.getInstance(document, outputStream);
    document.open();
    Font reportNameFont = FontFactory.getFont(FontFactory.HELVETICA, 14, Font.BOLD, Color.BLUE);
    document.add(new Paragraph("Report Name: " + argReportName, reportNameFont));
    // add a line break
    document.add(new Paragraph(""));

    Table table = new Table(columnCount);
    table.setWidth(100);
    table.setPadding(2);
    table.setSpacing(0);
    table.setCellsFitPage(true);
    table.setBorder(Rectangle.NO_BORDER);

    String columnNameHeader = null;
    Chunk chunkHeader = null;
    Cell cellHeader = null;
    float[] widths = new float[columnCount];
    //Preparing the column headers
    for (int i = 0; i < columnCount; i++) {
            columnNameHeader = metaData.getColumnLabel(i + 1);
            if(CsdcUtility.isBlank(columnNameHeader, true)) {
                columnNameHeader = "NoColumnName"+ i;
            }
            widths[i] = columnNameHeader.length();
            chunkHeader = new Chunk(columnNameHeader, new Font(Font.HELVETICA, 10, Font.BOLD));
            cellHeader = new Cell(chunkHeader);
            cellHeader.setHorizontalAlignment(Element.ALIGN_CENTER);
            cellHeader.setHeader(true);
            table.addCell(cellHeader);
    }
    table.endHeaders();

    int rowCount = 0;
    int columnType;
    String columnValue = "";
    Chunk chunk = null;
    Cell cell = null;
    Log.log("Preparing the column values");
    while (argResultSet.next()) {
        rowCount++;
        for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
            columnType = metaData.getColumnType(columnIndex + 1);
            columnValue = "";
            if(columnType == Types.BLOB || columnType == Types.CLOB || columnType == Types.LONGVARBINARY || columnType == Types.BINARY || columnType == Types.VARBINARY) {
                columnValue = new String(CSDCEncodeDecodeUtility.base64Encode(ExportExcel.getAsByteArray(argResultSet.getBlob(columnIndex + 1))));
            } else {
                columnValue = argResultSet.getString(columnIndex + 1);
            }
            if(CsdcUtility.isBlank(columnValue, true)) {
                columnValue = "";
            }
            if (widths[columnIndex] < columnValue.length()) {
                widths[columnIndex] = columnValue.length();
            }
            chunk = new Chunk(columnValue, new Font(Font.HELVETICA, 10));
            cell = new Cell(chunk);
            cell.setVerticalAlignment(Element.ALIGN_TOP);
            cell.setLeading(8);
            table.addCell(cell);
        }
    }
    //Table Prepared - Adding it to Document
    document.add(table); // **while adding the table to the document, throwing java heap space error**
    document.close();
    byteArray = outputStream.toByteArray(); 
    outputStream = null;
} catch(Exception e) {
    System.out.println(e.getStackTrace());
}
finally {
    if(document.isOpen()) {
        document.close();
    }
    try{
        if(argResultSet!=null){
            argResultSet.close();
            argResultSet=null;
        }
        if (outputStream != null)
        {
            outputStream.close();
            outputStream = null;
        }
    }catch (Exception e) {
        System.out.println(e.getStackTrace());
    }
}
return byteArray;
    }

2 个答案:

答案 0 :(得分:1)

您应该直接写入HttpServletResponse的输出流,而不是尝试在内存中创建字节数组。

答案 1 :(得分:0)

您正在使用ByteArrayOutputStream,此实现实际上会分配一个数组,并根据需要增长和复制数组的内容。

我建议您尝试使用另一个OutputStream - 您可以使用FileOutputStream写入临时文件夹,如果您关注IO和性能,请尝试查找另一个不能保留整个文件的实现串流(阵列)

**不要忘记关闭流,我看到你使ByteOutputStream无效,在其他实现中你需要确保正确关闭它们。