PDFBox 2.0.1挂起渲染pdf页面

时间:2016-06-09 11:36:04

标签: java pdfbox hang

我对PDFBox 2.0.1有一个问题,因为它无法呈现PDF。如果PDFBox在几个文件上失败,我真的不在乎,但问题是整个线程挂起并且几分钟内都没有返回,内存不断积累,看起来似乎并未结束

问题似乎与gridimg.setOnClickListener(this); llm = new LinearLayoutManager(ProductListActivity.this); rv = (RecyclerView)findViewById(R.id.recycler_viewproduts); rv.setLayoutManager(llm); 有关,这就是我所说的:

gridimg.setOnClickListener(this);
   llm =  new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
         rv = (RecyclerView)findViewById(R.id.recycler_viewproduts);

    rv.setLayoutManager(llm);

代码卡在该特定行上并消耗CPU和内存。在netbeans中,每当我暂停执行时,我都会看到这个堆栈跟踪。虽然我不确定发生了什么,因为我看到PDFBox工作但似乎已经遇到某种无限循环。

enter image description here

有问题的PDF可以从以下网址下载:https://drive.google.com/file/d/0B5zMlyl8rHwsY3Y1WjFVZlllajA/view?usp=sharing

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:3)

您使用的是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)启用子采样,这将减少用于图像的内存。

答案 1 :(得分:0)

该问题可以在Java 8 VM中重现。正如@Tilman在他的回答中已经提到的那样,这是Java 8使用与以前的Java版本不同的颜色管理系统引入的问题。

使用新的颜色管理系统分析虚拟机行为,很明显该问题实际上并不是内存泄漏问题(由于内存使用过多而推测);相反,对象的实例化速度比垃圾收集可以收集和释放未使用的对象更快!

通过更改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是我凭空选择的任意值。)

这仍然很慢但最终会创建位图而不会占用过多的内存。

因此,它看起来像旧的颜色管理系统实例化的方式更少的临时对象和/或明确允许垃圾收集介入。

PS: 上方的更改不会加快速度。它只是阻止了过多的内存使用观察到的OP以及在我的测试设置中导致了OutOfMemory情况。

如果OP完全控制部署环境,他确实应该使用@Tilman在他的回答中显示的选项。但是,如果OP没有,例如如果他最终部署到Web服务器上,他不管理,如果管理员不想添加到JVM启动选项,他至少可以防止过多的内存使用。