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

2023-09-04 00:45:17 作者:疯狗

我已经在过去的几天里寻找到这一点,我似乎无法弄清楚。

我有一个 C# 的WinForms 应用程序使用的ReportDocument 加载报告,并把它放入水晶报表查看器,让用户可以preVIEW它。的目的是preVIEW不同统计和形式永远不会关闭。还有运行和加载不同的报告到观众的计时器。

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

我读了很多关于互联网这个问题,我发现,无论是的ReportDocument 和浏览器需要关闭和处置。不幸的是,不解决它。在报告中的连接类型是 OLE DB(ADO)作为数据从 SQL服务器数据库检索。

简要发生的事情是Form1中有,当经过其配置的 Crystal报表查看并调用垃圾收集定时器。然后加载新的报告。

下面是示例code,我有

Form1的:

 私人的ReportDocument RPT;

私人无效timer2_Tick(对象发件人,EventArgs的)
{
    timer2.Enabled = FALSE;

    尝试
    {
          panel1.Hide();

          如果(RPT!= NULL)
          {
               的foreach(在rpd.Database.Tables表2)
                        t.Dispose();
               rpt.Close();
               rpt.Dispose();
               RPT = NULL;
               所以GC.Collect();
           }

           panel1.Controls.Remove(CRVviewer);
           如果(CRVviewer!= NULL)
           {
               CRVviewer.Dispose();
               所以GC.Collect();
           }

           //这个问题就从这里开始:

           VAR报告= navigationbar1.CurrentNode;
           RPT =新的ReportDocument();
           rpt.Load(@ report.Path,OpenReportMethod.OpenReportByDefault);

           rpt.ReportOptions.EnableSaveDataWithReport = FALSE;

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

           rpt.VerifyDatabase();

           //它到此为止

           CRVviewer =新的CrystalReportViewer();
           CRVviewer.ReportSource = RPT;
           CRVviewer.ShowLastPage();
           pagecount = CRVviewer.GetCurrentPageNumber();
           CRVviewer.ShowFirstPage();
           panel1.Controls.Add(CRVviewer);
           this.Update();
    }
    赶上(例外前)
    {
        ProcessErrors(前);
    }
    最后
    {
         timer2.Enabled = TRUE;
    }
}
 

这个问题是从数据库的连接,因为如果我打开一个本地报表,它工作正常。但是,我该怎么办错了?

解决方案

这是非常棘手与水晶报表的清理其与内存中创建的烂摊子。 (无意冒犯到SAP)

Crystal Reports课程01 连接SQL Sever数据库

您必须首先关闭和处置的的ReportDocument

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

,然后分配到空的的ReportViewer 和处置。

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

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

  GC.Collect的();
GC.WaitForPendingFinalizers();
所以GC.Collect();
 

  

请注意,一般不推荐调用GC.Collect(),但有时当内存是太大的问题和第三方COM组件的仿水晶报告问题得到妥善处理,我们可能不得不走这条路线的

I've spent the past few days looking into that and I can't seem to figure it out.

I have a c# WinForms application that uses the ReportDocument to load a report and put it into the Crystal Report Viewer, so that the user can preview it. The purpose is to preview different statistics and the form is never closed. There's a timer that runs and loads different reports into the viewer.

While that happens the memory usage and handles (I can see them in the task manager) keep increasing. When the application is started, it uses around 30 MB and when it runs for 10 minutes, it is then using around 200 MB and it keeps increasing.

I read a lot about this problem on the internet and I found that both the ReportDocument and the Viewer need to be closed and disposed. Unfortunately, that doesn't fix it. The connection type in the reports is OLE DB(ADO) as the data is retrieved from an SQL Server database.

Briefly what happens is that Form1 has a timer that when elapses it disposes the Crystal Reports Viewer and calls the garbage collector. And then loads the new report.

Here is the sample code that I have

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;
    }
}

The problem comes from the DB connections, because if I load a local report, it works fine. But what do I do wrong?

解决方案

It's very tricky with Crystal Report to clean up the mess it creates with memory. (No offence to SAP)

You will have to first close and dispose the ReportDocument

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

And then assign nulls to the ReportViewer and dispose.

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

And finally, you have to do the two pass GC collect.

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

Please note that it is generally not recommended to call GC.Collect() but sometimes when memory is too much of an issue and third party COM component's like crystal report has issue with getting disposed properly, we may have to go this route.