【问题标题】:CrystalReports ReportDocument memory leak with database connectionsCrystalReports ReportDocument 与数据库连接的内存泄漏
【发布时间】:2021-01-15 00:15:23
【问题描述】:

过去几天我一直在研究这个问题,但我似乎无法弄清楚。

我有一个c# WinForms 应用程序,它使用ReportDocument 加载报表并将其放入Crystal Report Viewer,以便用户可以预览它。目的是预览不同的统计数据,并且表单永远不会关闭。有一个计时器可以运行并将不同的报告加载到查看器中。

虽然发生这种情况,但内存使用量和句柄(我可以在任务管理器中看到它们)不断增加。当应用程序启动时,它使用大约 30 MB,当它运行 10 分钟时,它使用大约 200 MB,并且不断增加。

我在互联网上阅读了很多有关此问题的信息,发现ReportDocument 和查看器都需要关闭和处置。不幸的是,这并不能解决问题。报告中的连接类型为 OLE DB(ADO),因为数据是从 SQL Server 数据库中检索的。

简而言之,Form1 有一个计时器,当它经过时会释放Crystal Reports Viewer 并调用垃圾收集器。然后加载新报告。

这是我的示例代码

表格1:

private ReportDocument rpt;

private void timer2_Tick(object sender, EventArgs e)
{
    timer2.Enabled = false;

    try
    {
          panel1.Hide();

          if (rpt != null)
          {
               foreach (Table t in rpd.Database.Tables)
                        t.Dispose();
               rpt.Close();
               rpt.Dispose();
               rpt = null;
               GC.Collect();
           }

           panel1.Controls.Remove(CRVviewer);
           if (CRVviewer != null)
           {
               CRVviewer.Dispose();
               GC.Collect();
           }

           // The problem starts from here:

           var report = navigationbar1.CurrentNode;
           rpt = new ReportDocument();
           rpt.Load(@report.Path, OpenReportMethod.OpenReportByDefault);

           rpt.ReportOptions.EnableSaveDataWithReport = false;

           rpt.SetDatabaseLogon(report.UserId, report.Password);

           rpt.VerifyDatabase();

           // It ends here

           CRVviewer = new CrystalReportViewer();
           CRVviewer.ReportSource = rpt;
           CRVviewer.ShowLastPage();
           pagecount = CRVviewer.GetCurrentPageNumber();
           CRVviewer.ShowFirstPage();
           panel1.Controls.Add(CRVviewer);
           this.Update();
    }
    catch(Exception ex)
    {
        ProcessErrors(ex); 
    }
    finally
    {
         timer2.Enabled = true;
    }
}

问题来自数据库连接,因为如果我加载本地报告,它工作正常。但是我做错了什么?

【问题讨论】:

    标签: c# .net winforms memory-leaks crystal-reports


    【解决方案1】:

    Crystal Report 很难清理它用内存造成的混乱。 (无意冒犯 SAP)

    您必须先关闭并处置ReportDocument

    rpt.Close();
    rpt.Dispose();
    

    然后将空值分配给ReportViewer 并处理。

    CRViewer.ReportSource=null;
    CRViewer.Dispose();
    CRViewer=null;
    

    最后,你必须做两次 GC 收集。

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();
    

    请注意,一般不建议调用 GC.Collect() 但有时当内存问题太大,第三方 COM 组件(如水晶报表)无法正确处理时,我们可能不得不走这条路.

    【讨论】:

    • 谢谢,现在内存使用好像没问题,但是任务管理器中的句柄一直在增加。
    • 编辑:经过更多测试,内存使用量仍在增加。
    • 你可能想试试像 [dotMemory] ​​(jetbrains.com/dotmemory) 这样的内存分析器,它易于使用,并且有 5 天的免费试用期。当我遇到与 Crystal 报表类似的内存问题时,我借助此工具解决了我的内存问题。此外,您还需要密切关注任何已正确取消订阅的订阅事件,特别是如果您在这些事件中有任何水晶报告参考。我会尝试运行您的代码,看看是否可以找到任何其他问题?这是完整的代码吗?
    • 应用程序运行20多个小时后,我可以确认上述解决方案有效。可能这条线GC.WaitForPendingFinalizers(); 有很大的不同。
    • 我整天都在试图让这个查看器释放数据库连接。这似乎有效。谢谢!
    【解决方案2】:

    我找到了解决办法。 100% 工作。请安装水晶报表运行时版本 13_0_26。它为我修好了。最多只需 100 mb 即可生成 100 份报告。 新版本可能与您的 nuget 包不兼容,因此请相应更新您的参考。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      相关资源
      最近更新 更多