问题描述
过去几天我一直在研究这个问题,但我似乎无法弄清楚.
我有一个 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 与数据库连接的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!