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

多线程环境下任务陷入无限循环并耗尽内存:两段PDF处理代码的诱因排查

排查PDF处理代码中的无限循环与内存耗尽问题

嘿,我来帮你拆解这两段PDF处理代码里可能触发无限循环和内存耗尽的点——尤其在多线程环境下,这些问题很容易因为资源竞争或者不当的对象复用冒出来。

第一段代码的潜在问题

先看这段合并PDF的代码:

Document document = new Document(); 
using (FileStream newFileStream = new FileStream(tempFile, FileMode.Create, FileAccess.ReadWrite)) { 
    PdfCopy writer = new PdfCopy(document, newFileStream); 
    document.Open(); 
    foreach (var page in pages) { 
        PdfReader reader = new PdfReader(Path.Combine(pdfInputPath, page.PdfFileName)); 
        reader.ConsolidateNamedDestinations(); 
        PdfImportedPage importedPage = writer.GetImportedPage(reader, page.Page); 
        writer.AddPage(importedPage); 
        reader.Close(); 
    } 
    writer.Close(); 
    document.Close(); 
}

可能的诱因:

  • 非线程安全集合的并发修改:如果pages是普通的List<T>这类非线程安全集合,在多线程环境下,当这段代码遍历pages的同时,其他线程对pages执行了添加/删除操作,会导致枚举器失效,极端情况下可能陷入无限遍历。
  • 资源未正确释放导致的内存累积:Document和PdfCopy没有用using语句包裹,虽然手动调用了Close(),但如果遍历过程中抛出异常,这两个对象的资源可能无法正常释放。多次执行后内存占用持续攀升,最终触发OOM,而GC的频繁运行可能让程序看起来像是陷入了无限循环。
  • 无效页码的隐性循环(概率较低):如果page.Page的值超过了对应PDF的总页数,GetImportedPage会抛出异常,但如果外层有未显示的重试逻辑(比如循环重试直到成功),就可能导致无限循环。

第二段代码的潜在问题

再看这段给PDF添加内容的代码:

var reader = new PdfReader(pdfFile); 
using (var outputPdfStream = new FileStream(finalPDFPath, FileMode.Create, FileAccess.Write, FileShare.None)) { 
    var stamper = new PdfStamper(reader, outputPdfStream); 
    int i = 1; 
    foreach (var page in pages) { 
        var pdfContentByte = stamper.GetOverContent(i++); 
        string value = GetValue(); 
        if (!string.IsNullOrEmpty(value)) { 
            var img = GetPage(Information, page, layout, pdfContentByte, value, X_DPI, Y_DPI); 
            //var img = ImgRender(Information, page); 
            pdfContentByte.AddImage(img); 
            pdfContentByte.ClosePath(); 
        } 
    } 
    logger.Info("Number of pages after generation :" + reader.NumberOfPages); 
    stamper.Close(); 
    reader.Close(); 
}

可能的诱因:

  • GetPage方法内部的无限循环:你注释掉了ImgRender换成了GetPage,如果这个自定义方法在处理某些特定输入(比如多次调用后数据异常、图片资源损坏)时,内部存在逻辑漏洞(比如循环条件永远为真),会直接导致整个程序陷入无限循环。
  • pages集合与PDF页码不匹配+重试逻辑:如果pages的元素数量大于目标PDF的总页数,i++会超过reader.NumberOfPages,GetOverContent会抛出异常。如果外层有未显示的重试逻辑,就会不断循环重试。
  • 线程不安全对象的复用:PdfReader是在using外部创建的,如果多线程环境下多个请求复用了同一个PdfReader实例,会导致PdfStamper的内部状态混乱,可能触发异常或隐性的循环逻辑。
  • 资源泄漏导致的内存耗尽:PdfReader和PdfStamper没有用using包裹,异常情况下资源无法释放,多次执行后内存耗尽,GC频繁运行导致程序假死,看起来像无限循环。

另外,多线程环境下一定要确保每个请求都使用独立的Document、PdfCopy、PdfReader、PdfStamper实例——这些iText对象都不是线程安全的,共用实例会导致各种不可预测的问题,包括循环和内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 21:07:48