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

时间:2015-04-15 06:29:37

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

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

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

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

我在互联网上阅读了很多关于这个问题的内容,我发现ReportDocument和Viewer都需要关闭和处理。不幸的是,这并没有解决它。报告中的连接类型为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;
    }
}

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

1 个答案:

答案 0 :(得分:8)

使用 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组件像水晶报告有问题处理时,我们可能有走这条路。