PDFBox 2.0.1 挂起渲染 pdf 页面
PDFBox 2.0.1 hangs rendering pdf page
我对 PDFBox 2.0.1 有疑问,因为它无法呈现 PDF。我真的不在乎 PDFBox 是否在几个文件上失败,但问题是整个线程挂起并且从未 returns 几分钟并且内存不断增加并且似乎没有结束在望。
问题似乎出在 RenderImageWithDPI
,我是这样称呼它的:
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, 96); //Gets stuck here
ImageIO.write(image, "PNG", new File(fileName));
代码卡在该特定行并消耗 CPU 和内存。在 netbeans 中,每当我暂停执行时,我都会看到这个堆栈跟踪。虽然我不确定发生了什么,因为我看到 PDFBox 正在工作,但似乎遇到了某种无限循环。
相关 PDF 可从以下网址下载:https://drive.google.com/file/d/0B5zMlyl8rHwsY3Y1WjFVZlllajA/view?usp=sharing
有人可以帮忙吗?
你在 java 8 还是 java 9?如 here 所述,使用此选项启动 java:
-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
这与 JDK8/9 更改了他们的色彩管理系统有关。
文件呈现速度仍然很慢(20-30 秒),因为它非常复杂。
(顺便说一句,渲染没有挂起。只是花了非常非常长的时间,即几分钟)
自 PDFBox 2.0.9 以来的新功能:您提到您正在创建缩略图。您现在可以使用 PDFRender.setSubsamplingAllowed(true)
启用子采样,这将减少用于图像的内存。
此问题可以在 Java 8 VM 中重现。正如@Tilman 在他的回答中已经提到的,这是 Java 8 使用与以前的 Java 版本不同的颜色管理系统引入的问题。
使用新的颜色管理系统分析 VM 行为后,可以清楚地看出问题并不是真正的内存泄漏问题(可以推测是由于内存使用过多);相反,对象的实例化速度比垃圾收集收集和释放未使用对象的速度更快!
可以通过更改 PDFStreamEngine.processStreamOperators(PDContentStream)
中页面内容解析的主循环来允许垃圾回收:
int i = 1; // new
while (token != null)
{
if (token instanceof COSObject)
{
arguments.add(((COSObject) token).getObject());
}
else if (token instanceof Operator)
{
processOperator((Operator) token, arguments);
arguments = new ArrayList<COSBase>();
}
else
{
arguments.add((COSBase) token);
}
token = parser.parseNextToken();
if (i++ % 1000 == 0) // new
Runtime.getRuntime().gc(); // new
}
(1000
是我凭空选择的任意值。)
这仍然很慢,但它最终创建了位图而没有过多的内存使用。
因此,看起来较旧的颜色管理系统实例化的临时对象较少 and/or 明确允许垃圾收集介入。
PS: 上面的更改 并没有加快速度 。它只是 防止 OP 观察到的过度内存使用 并且在我的测试设置中导致了 OutOfMemory 情况。
如果 OP 可以完全控制部署环境,他确实应该使用他的回答中显示的选项@Tilman。但是,如果 OP 没有,例如如果他最终部署到他不管理的 Web 服务器上,并且如果管理员不想添加到 JVM 启动选项,他至少可以防止过度内存使用。
我对 PDFBox 2.0.1 有疑问,因为它无法呈现 PDF。我真的不在乎 PDFBox 是否在几个文件上失败,但问题是整个线程挂起并且从未 returns 几分钟并且内存不断增加并且似乎没有结束在望。
问题似乎出在 RenderImageWithDPI
,我是这样称呼它的:
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, 96); //Gets stuck here
ImageIO.write(image, "PNG", new File(fileName));
代码卡在该特定行并消耗 CPU 和内存。在 netbeans 中,每当我暂停执行时,我都会看到这个堆栈跟踪。虽然我不确定发生了什么,因为我看到 PDFBox 正在工作,但似乎遇到了某种无限循环。
相关 PDF 可从以下网址下载:https://drive.google.com/file/d/0B5zMlyl8rHwsY3Y1WjFVZlllajA/view?usp=sharing
有人可以帮忙吗?
你在 java 8 还是 java 9?如 here 所述,使用此选项启动 java:
-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
这与 JDK8/9 更改了他们的色彩管理系统有关。
文件呈现速度仍然很慢(20-30 秒),因为它非常复杂。
(顺便说一句,渲染没有挂起。只是花了非常非常长的时间,即几分钟)
自 PDFBox 2.0.9 以来的新功能:您提到您正在创建缩略图。您现在可以使用 PDFRender.setSubsamplingAllowed(true)
启用子采样,这将减少用于图像的内存。
此问题可以在 Java 8 VM 中重现。正如@Tilman 在他的回答中已经提到的,这是 Java 8 使用与以前的 Java 版本不同的颜色管理系统引入的问题。
使用新的颜色管理系统分析 VM 行为后,可以清楚地看出问题并不是真正的内存泄漏问题(可以推测是由于内存使用过多);相反,对象的实例化速度比垃圾收集收集和释放未使用对象的速度更快!
可以通过更改 PDFStreamEngine.processStreamOperators(PDContentStream)
中页面内容解析的主循环来允许垃圾回收:
int i = 1; // new
while (token != null)
{
if (token instanceof COSObject)
{
arguments.add(((COSObject) token).getObject());
}
else if (token instanceof Operator)
{
processOperator((Operator) token, arguments);
arguments = new ArrayList<COSBase>();
}
else
{
arguments.add((COSBase) token);
}
token = parser.parseNextToken();
if (i++ % 1000 == 0) // new
Runtime.getRuntime().gc(); // new
}
(1000
是我凭空选择的任意值。)
这仍然很慢,但它最终创建了位图而没有过多的内存使用。
因此,看起来较旧的颜色管理系统实例化的临时对象较少 and/or 明确允许垃圾收集介入。
PS: 上面的更改 并没有加快速度 。它只是 防止 OP 观察到的过度内存使用 并且在我的测试设置中导致了 OutOfMemory 情况。
如果 OP 可以完全控制部署环境,他确实应该使用他的回答中显示的选项@Tilman。但是,如果 OP 没有,例如如果他最终部署到他不管理的 Web 服务器上,并且如果管理员不想添加到 JVM 启动选项,他至少可以防止过度内存使用。