CrystalReports ReportDocument内存泄漏与数据库连接

Apo*_*fix 7 .net c# memory-leaks crystal-reports winforms

过去几天我一直在研究这个问题,我似乎无法弄明白.

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

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

我在互联网上阅读了很多关于这个问题的内容,我发现ReportDocument需要关闭和处理查看器.不幸的是,这并没有解决它.报告中的连接类型OLE DB(ADO)是从SQL Server数据库中检索数据.

简单地说,Form1有一个计时器,当它过去时它会处理Crystal Reports Viewer并调用垃圾收集器.然后加载新报告.

这是我的示例代码

Form1中:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

ANe*_*own 8

使用Crystal Report来清理它用内存创建的混乱是非常棘手的.(对SAP没有违法)

你必须先关闭并处理掉 ReportDocument

rpt.Close();
rpt.Dispose();
Run Code Online (Sandbox Code Playgroud)

然后将空值分配给ReportViewer和dispose.

CRViewer.ReportSource=null;
CRViewer.Dispose();
CRViewer=null;
Run Code Online (Sandbox Code Playgroud)

最后,你必须做两次通过GC收集.

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Run Code Online (Sandbox Code Playgroud)

请注意,通常不建议调用GC.Collect(),但有时当内存太多问题而第三方COM组件像水晶报告有问题处理时,我们可能不得不走这条路.