我的系统在处理一个大文件时抛出异常:“ java.lang.OutOfMemoryError:Java堆空间”。我意识到StringWriter.toString()会导致堆中的大小增加一倍,因此可能会导致此问题。我如何优化下面的代码块以避免内存不足。
public byte[] generateFromFo(final StringWriter foString) {
try {
StringReader foReader = new StringReader(foString.toString());
ByteArrayOutputStream pdfWriter = new ByteArrayOutputStream();
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, fopFactory.newFOUserAgent(),pdfWriter);
TRANSFORMER_FACTORY.newTransformer().transform(new StreamSource(foReader), new SAXResult(fop.getDefaultHandler()));
LOG.debug("Completed rendering PDF output!");
return pdfWriter.toByteArray();
} catch (Exception e) {
LOG.error("Error while generating PDF from FO",e);
throw new AuditReportExportServiceException(AuditErrorCode.INTERNAL_ERROR,"Could not generate PDF from XSL-FO");
}
}
答案 0 :(得分:2)
使用字节的InputStream可能会将foString的内存减少多达2倍(char = 2个字节)。
ByteArrayOutputStream在填充期间会调整大小,因此添加估计的需求会加快处理速度,并且可能会导致调整大小过多。
InputStream foReader = new ByteArrayInputStream(
foString.toString().getBytes(StandardCharsets.UTF_8);
foString.close();
final int initialCapacity = 160 * 1024;
ByteArrayOutputStream pdfWriter = new ByteArrayOutputStream(initialCapacity);
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, fopFactory.newFOUserAgent(),
pdfWriter);
TRANSFORMER_FACTORY.newTransformer().transform(new StreamSource(foReader),
new SAXResult(fop.getDefaultHandler()));
最好是更改API:
public void generateFromFo(final String foString, OutputStream pdfOut) { ... }
这可能会使ByteArrayOutputStream
变得多余,并且您可能会立即流式传输到文件,URL或其他任何内容。
文档本身和生成的PDF也存在问题:
答案 1 :(得分:1)
广泛地,您有两个主要选择:
增加进程可用的内存。 Java的-Xmx
选项将设置此配置。您可以通过例如-Xmx8G
要求64位系统上有8GB的内存(如果有的话)。文件在这里:http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html#nonstandard
将代码更改为以较小的块“流式传输”数据,而不是像在此所做的那样尝试将整个文件组装到内存中的byte[]
中。您可以将变压器的输出更改为FileOutputStream
而不是ByteArrayOutputStream
,并在显示的代码中返回File
而不是byte[]
吗?或者,根据您对该方法的输出进行处理,您可以返回InputStream
并允许使用者以流方式接收文件数据吗?
您可能还需要进行更改,以便以流方式使用此方法的输入。如何执行此操作取决于如何创建StringWriter foString
的详细信息。您可能需要将OutputStream
“管道”到InputStream
中才能完成这项工作,请参见https://docs.oracle.com/javase/7/docs/api/java/io/PipedInputStream.html
1更简单。这里2可能更好。