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

使用iTextPDF 7复制PDF页面时批量处理内存溢出问题排查

问题分析与修复方案

看起来你遇到的OutOfMemory异常,核心原因是大量PDF对象没有及时从内存刷新到磁盘,随着处理的文档数量增多,内存被持续占用最终耗尽。咱们来一步步拆解问题点和对应的修复方案:

核心内存泄漏根源

你的代码里有几个关键的资源释放遗漏:

1. 目标页面未执行刷新

每次创建的PdfPage page = pdfDest.addNewPage(PageSize.A4);在处理完后,没有调用page.flush();。在iText中,页面对象默认会暂存在内存里,直到整个文档关闭才会写入磁盘。当处理上百个文档、成百上千个页面时,这些堆积的页面对象会吃掉大量内存。

2. 目标文档未定期刷新

因为你的方法会被多次调用,用来给同一个目标PDF追加内容,如果不定期调用pdfDest.flush();,所有未写入磁盘的PDF对象都会一直留在内存中,内存占用只会越来越高。

3. 潜在的笔误问题

代码里sourcePage.copyAsFormXObject(pdfDestino);中的pdfDestino应该是pdfDest的笔误吧?如果这是实际代码里的错误,会导致额外的无效对象创建,进一步加重内存负担。

修复后的代码示例

try { 
    // 提前创建字体,避免循环中重复创建浪费内存
    PdfFont courierFont = PdfFontFactory.createFont(FontConstants.COURIER);
    
    for(int pageIndex = 1; pageIndex<=pdfSource.getNumberOfPages(); ++pageIndex) { 
        PdfPage sourcePage = pdfSource.getPage(pageIndex); 
        Rectangle sourceRect = sourcePage.getPageSizeWithRotation(); 
        PdfPage page = pdfDest.addNewPage(PageSize.A4); 
        PdfCanvas canvas = new PdfCanvas(page); 

        // 计算缩放变换矩阵
        AffineTransform transformationMatrix = AffineTransform.getScaleInstance( 
            (page.getPageSize().getWidth() / sourcePage.getWidth()) * 0.95, 
            (page.getPageSize().getHeight() / sourcePage.getHeight()) * 0.95); 
        canvas.concatMatrix(transformationMatrix); 

        try { 
            // 修正笔误:pdfDestino -> pdfDest
            PdfFormXObject pageCopy = sourcePage.copyAsFormXObject(pdfDest); 
            float x = (float)(page.getPageSize().getWidth()*0.05); 
            float y = (float)(page.getPageSize().getHeight()*0.05); 
            canvas.addXObject(pageCopy, x, y); 
            pageCopy.flush(); 
            // 刷新当前页面,释放内存中的页面对象
            page.flush();
        } catch(Exception e) { 
            // 建议添加日志记录,方便后续排查问题
            e.printStackTrace();
        } 

        // 重置变换矩阵准备添加页眉页脚
        transformationMatrix = AffineTransform.getScaleInstance( 
            sourceRect.getWidth() / page.getPageSize().getWidth(), 
            sourceRect.getHeight() / page.getPageSize().getHeight() 
        ); 
        canvas.concatMatrix(transformationMatrix); 
        canvas.setFillColorRgb(0.0f, 0.0f, 0.65f) 
            .setFontAndSize(courierFont, 11); 
        // 添加额外文本的逻辑...

        // 每处理20页就刷新一次目标文档,减少内存堆积
        if (pageIndex % 20 == 0) {
            pdfDest.flush();
        }
    } 
    // 当前文档处理完成后,务必刷新目标文档
    pdfDest.flush();
} finally { 
    pdfSource.close(); 
}

额外优化小贴士

  • 复用字体对象:原来的代码每次循环都创建新的Courier字体,这会产生大量重复的字体对象。现在把字体创建移到循环外,复用同一个对象,能节省不少内存。
  • 改用try-with-resources:对于PdfDocument这类可关闭资源,推荐用try-with-resources语法,它会自动帮你处理资源关闭,避免遗漏:
    try (PdfDocument pdfSource = new PdfDocument(new PdfReader("source.pdf"))) {
        // 循环处理页面的逻辑
    }
    
  • 监控内存变化:可以加个日志,记录每次循环后的内存使用情况,方便确认内存泄漏是否真的解决了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:09:47