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
16 Answers, 1 is accepted
Since I cannot upload my sample Project here I provide some Code Snippets:
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.
the Telerik team
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
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:
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.
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.
the Telerik team
Was this issue ever addressed?. I appear to have the exact same problem. Is there a workaround to unsubscribe from the exit event?
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.
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.
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.
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.
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?
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.
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
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.
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.
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.
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.