C#中用List存储数据库打印数据引发内存不足的解决方案咨询
解决C#打印大量数据时的OutOfMemoryException问题
嘿,遇到内存不足的问题确实头疼,尤其是打印大量数据的时候。咱们来一步步拆解问题,找到合适的解决方案:
核心原因分析
你现在的做法是把所有数据库数据一次性加载到List<FormName>中,当数据量超过300行(可能每行包含较大字段,比如文本、图片等)时,内存里会堆积大量对象,最终触发OutOfMemoryException。解决思路的核心就是减少内存中同时存在的数据量。
方案1:流式打印(推荐,内存占用最低)
直接放弃用List缓存所有数据,改为边从数据库读取边打印,内存里始终只保留当前处理的一行数据,彻底避免内存堆积。
修改后的代码示例:
// 不需要全局的List<FormName>了 public string printItemCode; public string printPartNo; public string printIssued; public string printUOM; // 数据库读取+打印逻辑 using (var rdr = cmd.ExecuteReader()) { int currentLine = 0; // 绑定PrintDocument的PrintPage事件,在事件中处理逐行打印和分页 PrintDocument pd = new PrintDocument(); pd.PrintPage += (sender, e) => { // 每次打印一页,直到数据读完 while (rdr.Read() && currentLine < pd.DefaultPageSettings.PrintableArea.Height / 20) // 假设每行高度20 { // 读取当前行数据 printItemCode = rdr["ItemCode"].ToString(); printPartNo = rdr["PartNo"].ToString(); printIssued = rdr["Issued"].ToString(); printUOM = rdr["UOM"].ToString(); // 绘制当前行到打印页面 e.Graphics.DrawString(printItemCode, new Font("Arial", 10), Brushes.Black, 10, currentLine * 20); e.Graphics.DrawString(printPartNo, new Font("Arial", 10), Brushes.Black, 100, currentLine * 20); // ...绘制其他字段 currentLine++; } // 如果还有未读数据,触发下一页打印 e.HasMorePages = rdr.HasRows; currentLine = 0; // 重置行号,准备下一页 }; // 开始打印 pd.Print(); }
这种方式的优势是内存占用极低,不管多少行数据,内存里都只有当前行和打印页面的临时对象。
方案2:分批加载打印(适合需要预览或批量处理的场景)
如果必须要缓存部分数据(比如打印预览需要提前加载几页),可以分批读取数据,打印完一批就清理内存,再加载下一批。
代码示例:
int batchSize = 50; // 每次加载50行,可根据内存情况调整 List<FormName> currentBatch = new List<FormName>(batchSize); using (var rdr = cmd.ExecuteReader()) { while (rdr.Read()) { FormName item = new FormName(); // 赋值属性 item.ItemCode = rdr["ItemCode"].ToString(); item.PartNo = rdr["PartNo"].ToString(); item.Issued = rdr["Issued"].ToString(); item.UOM = rdr["UOM"].ToString(); currentBatch.Add(item); // 批次满了就打印并清理 if (currentBatch.Count == batchSize) { PrintBatch(currentBatch); currentBatch.Clear(); // 清空批次,释放内存 // 内存紧张时可以主动提示GC回收(非必须,GC会自动处理) GC.Collect(); GC.WaitForPendingFinalizers(); } } // 打印剩余的不足一批的数据 if (currentBatch.Count > 0) { PrintBatch(currentBatch); currentBatch.Clear(); } } // 批量打印方法 private void PrintBatch(List<FormName> batch) { PrintDocument pd = new PrintDocument(); int currentLine = 0; pd.PrintPage += (sender, e) => { foreach (var item in batch) { if (currentLine >= pd.DefaultPageSettings.PrintableArea.Height / 20) { e.HasMorePages = true; currentLine = 0; return; } // 绘制当前项到页面 e.Graphics.DrawString(item.ItemCode, new Font("Arial", 10), Brushes.Black, 10, currentLine * 20); e.Graphics.DrawString(item.PartNo, new Font("Arial", 10), Brushes.Black, 100, currentLine * 20); // ...绘制其他字段 currentLine++; } e.HasMorePages = false; }; pd.Print(); }
额外优化建议
- 精简数据库查询:不要用
SELECT *,只选择打印需要的列(比如ItemCode, PartNo, Issued, UOM),减少数据传输和内存占用。 - 优化
FormName类:如果类中有大对象(比如byte[]存储图片、超长文本),而打印不需要这些字段,就不要加载它们,或者改为延迟加载。 - 检查打印资源释放:确保
PrintDocument、Graphics、Font等对象都正确调用Dispose(),避免内存泄漏。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

