tomcat - 解析要发送到 ftp 的 pdf 图像时内存泄漏/峰值
问题描述
我有一个 20MB 和 9 页的 PDF 文档,我正在尝试将其转换为图像并将它们 FTP,我正在使用 pdfBox(2.0.16 版本),下面的逻辑导致堆内存从小于 500 MB 2000MB的方式。我遵循了 pdf 框的常见问题解答(https://pdfbox.apache.org/2.0/faq.html#outofmemoryrrror),但到目前为止它没有帮助。我从当前的 2.0.16 版本升级到 2.0.20,但这也没有解决问题。任何有关错误的指示都将对我解决此问题非常有帮助。20 MB 文件的 1500 MB 内存增加很多,我正在通过 tomcat 运行我的应用程序,它使服务器崩溃。
PS:如果有其他我可以做的事情或更多细节,请告诉我。
代码:
PDDocument document = PDDocument.load(sourceFile,
MemoryUsageSetting.setupTempFileOnly());
PDFRenderer renderer = new PDFRenderer(document);
PDPageTree pdPageTree = document.getDocumentCatalog().getPages();
int pageNumber = 1;
strPdfFileName = strPdfFileName.replace(" ", "_");
UploadFileBuilder objUploadFileBuilder;
BufferedImage image;
File outputFile;
for (int i = 0; i < pdPageTree.getCount(); i++) {
strUploadFileName = new StringBuilder(strPdfFileName);
strUploadFileName.append("_").append(pageNumber).append(".png");
image = renderer.renderImage(pageNumber-1);
outputFile = new File(strPdfFilePath + File.separator + strPdfFileName +"_"+ pageNumber +".png");
LOGGER.debug("Image Created ----> {}", outputFile.getName());
ImageIO.write(image, "png", outputFile);
image.flush();
objUploadFileBuilder=new UploadFileBuilder();
objUploadFileBuilder.on(strUploadFileName.toString()).path(strFtpDir.toString()).withData(outputFile.getAbsolutePath());
lstUploadFileBuilder.add(objUploadFileBuilder);
strFileNameList.add(strUploadFileName.toString());
pageNumber++;
}
document.close();
UploadFileBuilder.execute(lstUploadFileBuilder);
Edit1:问题的堆栈跟踪,还进行了更改以刷新图像。
Edit2:当前 -XMX 设置(JVM 的最大内存分配池为 512m),我使用的是 java 1.8.0_91
解决方案
您可以尝试以下方法:
(1) 将以下依赖添加到您的maven项目中(如果您不使用maven,则手动添加)
<dependency>
<groupId>net.gredler</groupId>
<artifactId>jdk9-png-writer-backport</artifactId>
<version>1.0.0</version>
</dependency>
(2) 更改您的转换代码以使用 backportedWriter 和 FileCacheImageOutputStream:
private static void convertMethod2(File pdf) {
try (final PDDocument document = PDDocument.load(pdf)) {
PDFRenderer pdfRenderer = new PDFRenderer(document);
List<String> base64DocumentPages = new ArrayList<>();
for (int page = 0; page < document.getNumberOfPages(); ++page) {
BufferedImage bim = pdfRenderer.renderImage(page);
FileOutputStream baos = new FileOutputStream(strPdfFilePath + File.separator + strPdfFileName +"_"+ pageNumber +".png"););
PNGImageWriterBackport writer = chosePngWriter();
if(writer!=null) {
try (ImageOutputStream stream = new FileCacheImageOutputStream(baos,null)) {
writer.setOutput(stream);
writer.write(null,new IIOImage(bim, null, null), getImageParams(writer));
}
finally {
writer.dispose();
}
}
else {
System.err.println("PNGImageWriterBackport not found! Aborting");
}
//do what you need to do
}
document.close();
}
catch (IOException e) {
//handle exception
}
}
private static PNGImageWriterBackport chosePngWriter() {
Iterator<ImageWriter> imageWriters = ImageIO.getImageWritersByFormatName("png");
ImageWriter writer = null;
while(imageWriters.hasNext()) {
writer = imageWriters.next();
if (writer instanceof PNGImageWriterBackport) {
return (PNGImageWriterBackport)writer;
}
}
return null;
}
private static ImageWriteParam getImageParams(PNGImageWriterBackport writer) {
ImageWriteParam writeParam = writer.getDefaultWriteParam();
//set compression mode which wasn't possible before
writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
//0.0f highest compression, slowest
//1.0f lowest compression, fastest
writeParam.setCompressionQuality(0.86f);
return writeParam;
}
推荐阅读
- python-3.x - 如何使用热图 seaborn 子图 Python 3.6.0 中的不同间隔值自定义 cmap 中的每种颜色?
- powershell - 使用 Powershell/批处理命令卸载 MS Office 更新(知识库文章)
- windows - 对特定类型的文件运行命令
- python - 无法将表格导入熊猫
- mysql - 为什么 MySQL 在安装过程结束时不给我密码?
- powerbi - 从 Excel 上传到 Power BI 的数据丢失
- flutter - Flutter:防止 FutureBuilder 总是刷新每个更改屏幕
- python - Matplotlib 用双头箭头连接散点图
- c# - 大量的Task.Delay会不会导致性能问题
- node.js - 在 node.js 的生产服务器上获取 502 Bad Gateway