如何使用iTextSharp C#生成5000+页大型PDF报表且避免内存异常
如何用iTextSharp(C#)生成大型PDF报表并避免内存异常
问题根源
你的代码核心问题在于一次性将数百万条数据(甚至5亿条)全部存入PdfPTable后才写入文档,所有单元格数据会长期驻留在内存中,直接触发内存溢出。即使是5000页的报表,这种一次性加载的方式也会耗尽内存。
核心优化方案
1. 分批次写入表格,及时释放内存
不要将所有单元格都存在同一个PdfPTable实例中,而是每添加一批数据就写入文档,然后重置表格,让内存只保留当前批次的数据。
2. 启用Writer的即时磁盘刷新
通过配置PdfWriter的压缩和刷新机制,让iTextSharp及时将内存中的数据写入磁盘,而非一直缓存。
3. 复用资源减少内存开销
提前初始化字体、单元格格式等资源,避免在循环中重复创建,减少不必要的内存占用。
4. 关闭非必要的高精度设置
ByteBuffer.HIGH_PRECISION = true会增加内存消耗,非业务必需时建议关闭。
优化后的代码示例
// 初始化文档与Writer Document pdfDoc = new Document(PageSize.A3.Rotate(), 0, 0, 10, 10); FileStream stream = new FileStream(fileName, FileMode.Create); var writer = PdfWriter.GetInstance(pdfDoc, stream); // 启用全压缩,降低内存缓存 writer.SetFullCompression(); pdfDoc.Open(); // 提前初始化复用资源(避免循环内重复创建) var headerFont = fontHeaderFontAR; var cellFont = yourFont; // 写入表头 if (headerContent != null) { PdfPTable headerTable = new PdfPTable(1); headerTable.SpacingBefore = 30f; foreach (PDFHeaderItem item in headerContent.items) { headerTable.AddCell(CreateTitlePDFCell(Lang, item.ItemHeader, headerFont, headerContent)); headerTable.SpacingBefore = 10f; } pdfDoc.Add(headerTable); // 手动释放表头表格资源 headerTable = null; } // 分批次处理数据,示例每1000行一批(可根据内存情况调整) int batchSize = 1000; int totalRows = 500000; // 对应5000+页的实际数据量 for (int batchIndex = 0; batchIndex < totalRows; batchIndex += batchSize) { PdfPTable dataTable = new PdfPTable(1); // 计算当前批次的实际行数 int currentBatchCount = Math.Min(batchSize, totalRows - batchIndex); for (int i = 0; i < currentBatchCount; i++) { dataTable.AddCell(CreatePDFCell("TEXT", cell.KeyName, cellFont, cellFormats)); } // 写入当前批次表格 pdfDoc.Add(dataTable); // 强制刷新到磁盘,释放内存 writer.Flush(); // 释放当前批次表格资源 dataTable = null; // 按需触发垃圾回收(视内存压力调整) GC.Collect(); GC.WaitForPendingFinalizers(); } pdfDoc.Close(); stream.Close();
额外注意事项
- 分页加载数据源:如果数据来自数据库,使用分页查询每次只获取当前批次的数据,避免一次性加载全量数据到内存。
- 监控内存调整批次:根据实际运行环境的内存容量,调整
batchSize的大小,找到内存占用和生成速度的平衡点。 - 避免不必要的对象创建:循环内不要重复实例化字体、单元格样式等可复用对象。
内容的提问来源于stack exchange,提问作者Sivakumar
相关产品推荐
相关产品推荐

