PDFBox v3.0.0拆分PDF时出现StackOverflowError的解决方法
这个报错是因为PDFBox的COSWriterObjectStream在处理特定PDF的对象引用时,递归调用的深度超过了JVM默认的栈大小。通常是目标页面范围包含了嵌套层级极深,或者存在循环引用的PDF对象,触发了栈溢出。
下面是几个可行的解决办法:
调整JVM栈内存
最简单的临时修复是增大JVM栈大小,启动程序时添加参数-Xss2m(将栈大小设置为2MB,可根据实际情况调整到-Xss4m这类更大的值)。不过要注意,过大的栈内存可能会挤占堆内存,导致其他内存问题,按需调整即可。规范Splitter类的使用
如果用的是PDFBox自带的Splitter,不要复用同一个实例处理多个页面范围——每次拆分新的范围都新建Splitter对象。同时,拆分完成后务必及时关闭生成的子文档,避免对象引用堆积:try (PDDocument sourceDoc = PDDocument.load(new File("source.pdf"))) { // 每个范围都新建Splitter Splitter splitter = new Splitter(); splitter.setStartPage(range.getStart()); splitter.setEndPage(range.getEnd()); List<PDDocument> splitDocs = splitter.split(sourceDoc); for (PDDocument doc : splitDocs) { try { doc.save("output_" + range.getStart() + "_" + range.getEnd() + ".pdf"); } finally { // 必须关闭子文档 doc.close(); } } } catch (IOException e) { e.printStackTrace(); }优化自定义拆分逻辑
如果你用了自己写的拆分逻辑,别手动递归处理PDF对象,尽量用PDFBox提供的工具类来复制页面和资源。比如调用PDDocument.addPage()时,确保页面关联的资源是被正确复制的,不要保留对源文档对象的深层引用。另外,尝试用PDDocument.saveIncremental()替代普通的save(),能减少递归处理的层级。预处理源PDF
对存在深层嵌套或循环引用的源PDF,先用PDFBox的PDFOptimizer优化一遍,压缩对象层级、清理无效引用:try (PDDocument sourceDoc = PDDocument.load(new File("source.pdf"))) { PDFOptimizer optimizer = new PDFOptimizer(); optimizer.optimize(sourceDoc, new File("optimized_source.pdf")); } catch (IOException e) { e.printStackTrace(); }用优化后的文档进行拆分,能大幅降低递归栈溢出的概率。
升级PDFBox版本
旧版本的PDFBox可能存在递归处理的bug,直接升级到最新的稳定版(比如2.0.x系列的最新版本),官方大概率已经修复了这类栈溢出问题。
内容的提问来源于stack exchange,提问作者malz

