我的系统在处理一个巨大的文件时抛出异常:“ 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");
}
}
最佳答案
使用字节的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也存在以下问题:
图像尺寸(但请记住打印分辨率较高)
一些图像可以很好地矢量化
重复的图像(如页面标题中的图像)应存储一次
理想情况下,字体应该是标准字体,是(使用过的字符)第二好的嵌入式子集
XML可能不是最佳选择,非常重复