2016-04-18 68 views
0

当我们尝试导出为PDF时,我们正面临Java堆空间错误。下面是堆栈跟踪错误,下载PDF文件时从itext获取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; 
    } 
+0

我会从一个更大的堆开始,看看它是否仍然发生。你如何设置最大堆到80%的主内存或32 GB的更小。或者你可以使用内存分析器(内置两个内存)来查看你的内存消耗的位置。 –

+0

你用iText 5.5.9试过吗?因为您使用的是10年前的版本。软件世界中的10年*古代*。 –

回答

0

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

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

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

0

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

+0

虽然内存明显更可取,但这不适用于所有HTTP客户端:某些客户端需要内容长度标题,但在创建PDF之前不知道内容长度。 – mkl