Memory Leak using WPF ReportViewer

17 posts, 0 answers
  1. JULIA
    JULIA avatar
    62 posts
    Member since:
    Jun 2011

    Posted 01 Mar 2011 Link to this post

    Hello,

    I am using a MVVM Pattern for my Application, which contains several WPF ReportViewers. They are bound to Reports, stored in public Properties of the ViewModels as you have shown in this Forum.

    The Problem is, that the Views containing these Reports are never disposed. Normaly once the ContentPresenter (TabControl or something) no longer contains a reference to the ViewModel, itself along with the appropriate View (UserControl) are beeing disposed.

    Memory Profiler shows that the ReportViewer contains RadSliders, those are connected via SizeChangedEventHandlers to the MainView and that keeps them alive in Memory. Closing the MainView would of course close the Application, so that is no Solution.

    As you can see in my Sample Application, if you Load and Remove the Report 20 Times the small App already needs 500MB of Memory.

    Can you provide me with some way to remove those unneeded ReportsViewers, without having to open an additional Window for the Viewer?

    thank you very much

    Timo

  2. JULIA
    JULIA avatar
    62 posts
    Member since:
    Jun 2011

    Posted 01 Mar 2011 Link to this post

    Since I cannot upload my sample Project here I provide some Code Snippets:

    ContentPresenter:

    <ContentPresenter Grid.Row="1" Content="{Binding ReportVM}"  />

    Report Property:

    /// <summary>
           /// Eigenschaft Report
           /// </summary>
           public Report ErrorReport
           {
               get { return _errorReport; }
               set
               {
                   if (_errorReport == value)
                   {
                       return;
                   }
                   _errorReport = value;
                   RaisePropertyChanged("ErrorReport");
               }
           }
           private Report _errorReport;

    ReportViewModel Property:

    /// <summary>
           /// Eigenschaft ReportVM
           /// </summary>
           public ErrorReportViewModel ReportVM
           {
               get { return _reportVM; }
               set
               {
                   if (_reportVM == value)
                   {
                       return;
                   }
                   _reportVM = value;
                   RaisePropertyChanged("ReportVM");
               }
           }
           private ErrorReportViewModel _reportVM;

    ReportViewer Binding:

    <telerik:ReportViewer Grid.Row="0" Margin="10" x:Name="ReportViewer1" Report="{Binding DataContext.ErrorReport, ElementName=thisWindow}" />

  3. Chavdar
    Admin
    Chavdar avatar
    898 posts

    Posted 02 Mar 2011 Link to this post

    Hi Diiimo,

    It is not sure that the 'memory leak' is caused by the report viewer as it does not attach any event handlers to external elements or models. In this way it cannot be referenced from outside and once destroyed it should free the entire memory.

    Greetings,
    Chavdar
    the Telerik team
    Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
  4. Anthony
    Anthony avatar
    4 posts
    Member since:
    Dec 2010

    Posted 28 Nov 2011 Link to this post

    Hi Chavdar / Timo

    I too am getting an issue similar to this, has a resolution been found yet? 

    Unfortunately I can't upload the source for my current project but attached is an instance retention graph produced using ANTS Memory Profiler showing the Telerik ReportViewer being kept in memory by a binding to the main window ExitEventHandler. If you need any extra information please let me know


    Cheers

  5. Anthony
    Anthony avatar
    4 posts
    Member since:
    Dec 2010

    Posted 29 Nov 2011 Link to this post

    Just to provide a few more details:

    The project is a WPF application using the Managed Extensibility Framework (MEF) providing a dynamic tabbed interface (similar to Firefox, Chrome, IE etc.) for which each tab can have a particular plugin loaded. Tabs can be opened / closed as many times as a user likes and one plugin in particular contains Telerik reports. When tabs with Telerik reports are closed the memory consumed by them is not released. We have confirmed this by implementing an empty object in place of the Telerik reports and compared memory usage. Eliminating the Telerik reports solves the issue. On further inspection using ANTS (see attached PNG image in previous post), it would appear the Telerik Reports  'ReportViewerModel' is somehow binding to the main application's ExitEventHandler. Closing the main application is not an option hence somehow the link between the ReportViewer and the ExitEventHandler must be broken. I've tried shifting the Reporting Initialization code from XAML to the code behind and it looks something like this:

    private ReportViewer reportViewer = new ReportViewer();

    public
    ReportingUserControl(string serverConnectionString, bool isPreloading)
    {
    InitializeComponent();
    reportViewer.SetValue(Grid.ColumnProperty, 2);
    reportViewer.SetValue(MarginProperty,
    new Thickness(0))
    gridMain.Children.Add(reportViewer);

    \\ More Code Here
    }

    however the same memory issue still occurs. At no point are any of the Events provided by the ReportViewer being subscribed to by the UserControl.




  6. Chavdar
    Admin
    Chavdar avatar
    898 posts

    Posted 29 Nov 2011 Link to this post

    Hi Anthony,

    The ReportViewerModel really attaches to the Exit event handler of the application. This is done on purpose in order to delete the temporary files that have been created to store the viewer's resources such as pages and images.

    Your case, however, seems reasonable so we will log a work item for this issue and try to find a better approach or at least reduce the amount of memory being used. Once it is implemented you will find a record in the accompanying release notes.

    Please note, that the Exit event was first utilized in the Q2 2011 release of Telerik Reporting which was released after my first answer to the problem.

    Best wishes,
    Chavdar
    the Telerik team

    Q3’11 of Telerik Reporting is available for download. Register for the What's New in Data Tools webinar to see what's new and get a chance to WIN A FREE LICENSE!

  7. Ian
    Ian avatar
    7 posts
    Member since:
    May 2009

    Posted 12 Sep 2018 in reply to Chavdar Link to this post

    Hi,

     

    Was this issue ever addressed?.  I appear to have the exact same problem.  Is there a workaround to unsubscribe from the exit event?

  8. Ian
    Ian avatar
    7 posts
    Member since:
    May 2009

    Posted 12 Sep 2018 Link to this post

    If it is not possible to unsubscribe to the exit event, then can you please advise a way for the raw data associated with the processed report (Telerik.Reporting.Processings.Data.ObjectDataEnumberable.DataObject) to be cleared from memory. I've tried clearing the report datasource but it seems that ReportViewerModel (via ServerReportViewerHistoryRecord) is holding a reference to the objects I need to remove from memory.

     

    Thanks

  9. Todor
    Admin
    Todor avatar
    321 posts

    Posted 17 Sep 2018 Link to this post

    Hi Ian,

    The bug related to the Exit event handler of the application has been fixed with Telerik Reporting Q3 2011 SP1.

    Note that the viewer indeed holds references to the previously opened reports so that the history-related functionality of the viewer to work properly. When the ReportViewerModel is disposed (on Window.Closed event of the window that hosts the viewer), all the resources associated with the viewer are also disposed.

    Please, specify the version of Telerik Reporting where the problem occurs.
    I suggest to open a support ticket and send us a sample project experiencing the issue for local investigation.

    Regards,
    Todor
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  10. Ian
    Ian avatar
    7 posts
    Member since:
    May 2009

    Posted 17 Sep 2018 in reply to Todor Link to this post

    Hi Todor,

     

    Thanks for the reply.  I'm using Telerik Reporting R2 2018.  I can confirm that the ReportViewModel is not being disposed.  I wonder whether it is because I'm hosting the viewer in a RadDocumentPane (Docking control) i.e.does a Window.Closed event fire on Dock.Close event?

    Could you please advise a workaround if this is this is the root cause.

     

    Thanks

     

    Ian

  11. Todor
    Admin
    Todor avatar
    321 posts

    Posted 20 Sep 2018 Link to this post

    Hello Ian,

    Window.Closed event fires only when the window gets closed, hence on Dock.Close event the ReportViewerModel will not be disposed.
    We discussed the issue in the team and will probably provide means for manually disposing the ReportViewerModel to properly cover also cases as yours.
    Check our Release History for updates on the matter. The improvement should be available with one of the upcoming service packs.

    Meanwhile, you may use the ClearHistory() method to reduce the amount of occupied memory. The method will remove all the reports rendered previously and will leave only the last (current) one. If you set the report source to null before closing the viewer and then call ClearHistory() there will be no reports left in memory.

    Regards,
    Todor
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  12. Matt
    Matt avatar
    11 posts
    Member since:
    Jan 2013

    Posted 13 Jun in reply to Todor Link to this post

    Any update on this?  It has been over 7 years since this was first reported.
    I lost a lot of time in searching through my code for memory leaks when the problem was in fact with the ReportViewer control.

    What purpose is served in having the ReportViewer control handle Window.Closed events?
    If it wasn't tied to the lifecycle of the window, wouldn't it naturally dispose of itself properly once unloaded?

  13. Todor
    Admin
    Todor avatar
    321 posts

    Posted 18 Jun Link to this post

    Hello Matt,

    The ReportViewerModel implements IDisposable as it creates unmanaged resources that need to be disposed first and holds references to event handlers that need to be disattached.

    The purpose of handling the Window.Closed event is when the report viewer's parent window is closed, the report viewer's resources and its model to be disposed in order to free up memory and optimize the visual tree. We still haven't provided means to manually dispose of the viewer's model.

    Regards,
    Todor
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  14. Matt
    Matt avatar
    11 posts
    Member since:
    Jan 2013

    Posted 18 Jun in reply to Todor Link to this post

    Thanks for the reply Todor.

    In looking at the disassembly, the OnWindowClosed method is the only place where the Window.Closed event handler is removed.

    Should this not also be done within the OnUnloaded method?

    Also, as you mentioned, the OnWindowClosed event calls into the following two methods
                this.DetachModelEventHandlers();
                this.DisposeModel();

    Whereas OnUnloaded only calls this.DetachModelEventHandlers();

    Should the OnUnloaded and OnWindowClosed not essentially perform the same function?

    The easiest thing to do here, in my view, would be to create an event relay between the ReportViewer and the Window.  The relay would hold onto the ReportViewer through a WeakReference and route calls to its event handler to the ReportViewer.  This way the Window is not holding onto a dead ReportViewer until the Window itself closes.

     

    Also within the disassembled code I do not see ReportViewerModel implementing IDisposable.

  15. Ivan Hristov
    Admin
    Ivan Hristov avatar
    203 posts

    Posted 21 Jun Link to this post

    Hello Matthew,

    Thank you for your efforts to pinpoint the issue - it's always nice to see someone employing a disassembly tool to see how the things are implemented.

    First, I want to apologize for a mistake made in the previous answers: the ReportViewerModel is not disposable and does not implement IDisposable. It contains resources that need to be disposed (like history records, rendered pages, processed reports, etc.). The confusion probably comes from the fact that there is a method in the ReportViewer incorrectly named DisposeModel(), which calls the routines for releasing the allocated resources. However, for brevity below I will use "dispose" in sense that the actual model instance will not be disposed, but its resources and event handlers will be disposed.

    Now, about the OnUnloaded() and OnWindowClosed() events. They should not perform the same operations, because they serve different scenarios. OnWindowClosed() is the last possible moment when all the events must be detached and resources must be released. OnUnloaded(), on the other hand, will be called when the control is removed from the visual tree but that may not require releasing the model and its resources. For example, when the ReportViewer is hosted in a RadTabControl, switching off the tab will raise the OnUnloaded() event. In this case the tab that contains the ReportViewer should not "dispose" the model, because when the tab is switched on again, the model will reload the report and that's unexpected to the users.. That's why we're only detaching the event handlers but the model is kept alive so when the tab raises OnLoaded() event, the events will be reattached and the report will be displayed without reloading.

    Ultimately we do not want to have a window with a "dead" ReportViewer in it. As long as the window is not closed, the ReportViewer must be accessible. Therefore closing the window must call the logic of releasing the resources allocated by the viewer and its model. We're aware that in some scenarios this logic might not fit, that's why we plan to publicly expose the initializing and disposing events, so the developers will have more control on them. In a scenario described earlier in this thread, the user noticed that the Dock.Close does not dispose the report viewer. and that's right - Dock.Close doesn't perform OnWindowClosed() so the viewer is still alive due to the reasons I explained above with the RadTabControl scenario. Having the public disposing methods should resolve this problem.

    One particular scenario that requires more attention is when the ReportViewer is hosted in a RadWindow. The RadWindow allows to be closed and then shown again, which cannot be done with the framework's Window control. In this case the ReportViewer "disposes" the model on WindowClosed() but does not instantiate it on Shown() and the application throws an exception. The solution is to instantiate the RadWindow again so the model gets properly initialized.

    I hope my post explains why the report viewer is designed this way and which are the expected usage scenarios. Of course, if you need further assistance or some details here were obscure, please do not hesitate to ask.

    Regards,
    Ivan Hristov
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  16. Matt
    Matt avatar
    11 posts
    Member since:
    Jan 2013

    Posted 21 Jun in reply to Ivan Hristov Link to this post

    Hi Ivan,

    Thanks for the detailed reply.

    Regarding the OnUnloaded vs OnWindowClosed I can appreciate this difference in scenarios.  My comments above were based on testing with an older version where when we had the ReportViewer placed within a standard TabControl the report model would reload whenever the current tab was changed.  I'm not sure with which version we experienced this, but I am glad it is resolved as we can remove some workarounds we used.

    I look forward to be able to better control the initialization/disposal of the ReportViewer.  Hopefully sooner rather than later.

  17. Ivan Hristov
    Admin
    Ivan Hristov avatar
    203 posts

    Posted 24 Jun Link to this post

    Hello Matthew,

    I'm glad my explanation made sense to you and hopefully will help the other users that read the thread understand why and how the things happen under the hood. Just FYI: the fix that changes the behavior in OnUnloaded and OnWindowClosed events is published in R1 2017 SP2 release. We'll increase the priority of the code change that will expose the related events of the report viewer. As soon it is ready, we'll include it in the subsequent internal build so you can download it and give it a try.

    Regards,
    Ivan Hristov
    Progress Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top