You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PDFBox Splitter拆分多PDF后遇OutOfMemoryError问题咨询

问题

我有一批PDF文件需要拆分为单页PDF。编写的脚本在处理单个或少量文件时正常,但处理总计6000页的多份PDF时,最终会出现内存不足,并打印提示Warning: You did not close a PDF Document。通过设置MemoryUsageSetting.setupMixed(50_000_000)降低内存配置后可运行,但设置为200MB时仍会内存不足。我认为PDFBox内部存在未关闭的COSDocument,这也是出现警告的原因。我确认已关闭所有创建的PDDocument,甚至编写代码检查所有可访问的实例,但相关日志并未输出。

以下是我的代码:

int splitPdf( File pdfFile ) {
    String filePrefix = prefix
    if( !filePrefix ) filePrefix = pdfFile.name[0..<(pdfFile.name.lastIndexOf("."))]
    logger.info("Splitting ${pdfFile.name} pages ${startAtPage} - ${endAtPage} every ${splitPagesEvery} pages")
    PDDocument document = PDDocument.load( pdfFile, MemoryUsageSetting.setupTempFileOnly() )
    try {
        Splitter splitter = new Splitter()
        splitter.setStartPage(startAtPage)
        splitter.setEndPage(endAtPage)
        splitter.setSplitAtPage(splitPagesEvery)
        splitter.memoryUsageSetting = MemoryUsageSetting.setupMixed(50_000_000)
        int page = startAtPage > 0 ? startAtPage : 1
        splitter.split(document).each { PDDocument doc ->
            String filename = "${filePrefix}-${page}.pdf"
            try {
                if( extractions ) {
                    PDFTextStripper stripper = new PDFTextStripper()
                    String pageText = stripper.getText( doc )
                    Map<String,String> results = extractions.collectEntries([filename: filename]) { name, spec ->
                        [ name, spec.call(pageText) ]
                    }
                    this.manifest.write(results)
                }
                doc.save( new File( destDir, filename) )
                page++
            } finally {
                doc.close()
                if( !doc.document.isClosed() ) logger.info("${filename} is NOT closed!")
            }
        }
        return page - startAtPage
    } finally {
        document.close()
        if( !document.document.isClosed() ) logger.info("${pdfFile.name} is NOT closed!")
    }
}

我暂无证据证明PDFBox 2.0.29存在内存泄漏,但无法解释为何会出现大量未关闭PDF文档的警告。我正准备编写脚本通过分析器查看COSDocument实例数量是否远超预期。我的问题是:在执行页面拆分时,PDFBox内部是否可能会创建未被释放的额外COSDocument?

回答

在PDFBox的Splitter拆分流程中,确实存在内部创建额外COSDocument但未被及时释放的可能性,尤其是处理大文件或多页文档时:

  • Splitter内部实现的隐性实例
    Splitter拆分时会为每个子文档创建新的COSDocument,但如果拆分过程中出现隐性异常(比如资源读取中断),部分临时COSDocument可能未关联到返回的PDDocument对象中,导致无法通过你代码里的doc.close()触发关闭。

  • PDFTextStripper的残留资源
    你使用PDFTextStripper提取文本时,该工具内部会生成临时解析对象,这些对象依赖文档的关闭时机回收资源。若文本提取过程中出现未捕获的隐性错误,可能导致部分COSDocument引用残留。

  • 内存配置与回收的延迟冲突
    当设置MemoryUsageSetting.setupMixed时,PDFBox会在内存和临时文件间切换存储,但如果临时文件清理不及时,加上JVM垃圾回收延迟,会造成COSDocument实例堆积,触发内存不足和未关闭警告。

  • 排查方向建议

    • 改用Splitter.setSplitAtPage(1)直接拆分为单页,减少拆分过程中的中间文档实例
    • 检查manifest.write(results)是否存在IO阻塞,导致文档对象无法及时被回收
    • 用分析器跟踪COSDocument的创建/销毁路径,重点查看Splitter.split()方法内部的对象处理逻辑

内容的提问来源于stack exchange,提问作者chubbsondubs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:05:21