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 启动选项,他至少可以防止过度内存使用。