过去几天我一直在研究这个问题,我似乎无法弄明白。
我有一个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;
}
}
问题来自数据库连接,因为如果我加载本地报告,它可以正常工作。但是我做错了什么?
答案 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组件像水晶报告有问题处理时,我们可能有走这条路。