2015-04-15 14 views
5

Spędziłem kilka ostatnich dni na zaglądaniu w to i nie mogę tego zrozumieć.CrystalReports ReportDocument wyciek pamięci z połączeniami z bazami danych

Mam aplikację c#WinForms, która używa ReportDocument do załadowania raportu i umieszczenia go w przeglądarce Crystal Report Viewer, aby użytkownik mógł wyświetlić podgląd. Celem jest podgląd różnych statystyk, a formularz nigdy nie jest zamknięty. Jest zegar, który uruchamia się i ładuje różne raporty do przeglądarki.

Podczas gdy tak się dzieje, zużycie pamięci i obsługuje (widzę je w menedżerze zadań) nadal rośnie. Po uruchomieniu aplikacji zużywa około 30 MB, a gdy działa przez 10 minut, wykorzystuje około 200 MB i stale rośnie.

Dużo czytałem o tym problemie w Internecie i odkryłem, że zarówno ReportDocument, jak i Viewer muszą zostać zamknięte i usunięte. Niestety to nie naprawia. Typ połączenia w raportach to OLE DB(ADO), ponieważ dane są pobierane z bazy danych SQL Server.

Krótko mówiąc, Form1 ma zegar, który po upłynięciu wywołuje Crystal Reports Viewer i wywołuje funkcję czyszczenia pamięci. A następnie ładuje nowy raport.

Oto przykładowy kod, który mam

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

Problem pochodzi z połączenia DB, bo jeśli załadować raportu lokalnego, to działa dobrze. Ale co mam zrobić źle?

Odpowiedz

7

To bardzo trudne z Crystal Report, aby posprzątać bałagan, który tworzy z pamięci. (Bez urazy do SAP)

Trzeba będzie najpierw zamknąć i wyrzucać ReportDocument

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

a następnie przypisać wartości null do ReportViewer i wyrzucać.

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

I wreszcie, musisz wykonać dwukanałowe pobranie GC.

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

Należy pamiętać, że ogół nie zaleca się zadzwonić GC.Collect(), ale czasami, kiedy pamięć jest zbyt wiele kwestii i komponentów COM strona trzecia jest jak kryształ raportu problem z uzyskaniem umieszczony prawidłowo, mamy może trzeba iść tą drogą.

+0

Dzięki temu użycie pamięci wydaje się teraz być w porządku, ale uchwyty w menedżerze zadań wciąż rosną. – Apostrofix

+0

EDYCJA: A po kolejnych testach zużycie pamięci wciąż rośnie. – Apostrofix

+1

Możesz chcieć wypróbować profiler pamięci jak [dotMemory] (https://www.jetbrains.com/dotmemory/) Ten jest łatwy w użyciu i ma 5 dni darmowej wersji próbnej. Rozwiązałem problem z pamięcią za pomocą tego narzędzia, gdy miałem podobne problemy z pamięcią w raportach Crystal. Co więcej, Ty też chcesz śledzić wszystkie subskrybowane zdarzenia, które zostały prawidłowo anulowane, szczególnie jeśli masz odniesienie do kryształów w tych wydarzeniach. Spróbuję uruchomić twój kod i sprawdzić, czy mogę znaleźć inny problem? czy to pełny kod? – ANewGuyInTown