CrystalReports ReportDocument 与数据库连接的内存泄漏 [英] CrystalReports ReportDocument memory leak with database connections

查看:22
本文介绍了CrystalReports ReportDocument 与数据库连接的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

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

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

这是我的示例代码

表格1:

私人 ReportDocument rpt;private void timer2_Tick(对象发送者,EventArgs e){timer2.Enabled = false;尝试{panel1.Hide();如果(rpt!= null){foreach(rpd.Database.Tables 中的表 t)t.Dispose();rpt.Close();rpt.Dispose();rpt = 空;GC.Collect();}panel1.Controls.Remove(CRVviewer);如果(CRVviewer != null){CRVviewer.Dispose();GC.Collect();}//问题从这里开始:var 报告 = 导航栏 1.CurrentNode;rpt = new ReportDocument();rpt.Load(@report.Path, OpenReportMethod.OpenReportByDefault);rpt.ReportOptions.EnableSaveDataWithReport = false;rpt.SetDatabaseLogon(report.UserId, report.Password);rpt.VerifyDatabase();//到此结束CRVviewer = new CrystalReportViewer();CRVviewer.ReportSource = rpt;CRVviewer.ShowLastPage();pagecount = CRVviewer.GetCurrentPageNumber();CRVviewer.ShowFirstPage();panel1.Controls.Add(CRVviewer);this.Update();}捕捉(异常前){进程错误(例如);}最后{timer2.Enabled = true;}}

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

解决方案

Crystal Report 清理它用内存造成的混乱非常棘手.(无意冒犯 SAP)

您必须先关闭并处理 ReportDocument

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

然后将空值赋给ReportViewer并处理.

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

最后,你必须做两次 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.

这篇关于CrystalReports ReportDocument 与数据库连接的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆