Hello,
In our application we use on different places XafReports.
For example for creating invoices each month. This invoices are sometimes printed. Not 4 but 150+.
Because of the heavy operation one of our customers had a OutOfMemoryException.
After searching for the problem we analyse the memory with .NET memory analyzer.
We found a memory leak in XafReports. We have tried in the maindemo too and can reproduce the problem.
The steps to reproduce:
- Open an report
- Close the report
- Open the other report (you get the popup for task status)
- Close the popup
- Open again the first report
- Close the report.
I had the following results (graph of results in attachment):
* The application before opening: 20.472.716 bytes (~20.4 MB) (Point 1 in image)
* When report is opened: 22.933.581 bytes (~22.9 MB) (Point 2 in image)
* When closing the report: 23.655.589 bytes (~23.6 MB) (Point 3 in image)
* GC cleans up: 22.188.319 bytes (~22.2 MB) (Point 4 in image)
* Other report opened: 24.256.107 bytes (~24.3 MB) (Point 5 in image)
* Close the report: 23.514.175 bytes (~23.5 MB) (Point 6 in image)
* Open the first report again: 24.102.956 bytes (~24.1 MB) (Point 7 in image)
* Close report: 24.608.736 bytes (~24.6 MB) (Point 8 in image)
With this numbers we can make the conclusion that for some reason not everything is cleaned up correctly and the memory goes up.
Ok, this is a small application with 2 reports which are opened and closed again twice. However in our application we have at least 500 reports so the impact will be bigger and bigger.
Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.
Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.
Thank you for your report. We need additional time to replicate and research this issue. We will get back once we have any result.
Hello,
Thank you for contacting us. I am afraid we could not replicate the issue. Please review the attached video, which demonstrates our attempts, and let me what steps are missing, if any.
The problem may occur in a case when many objects are loaded to an ObjectSpace, and the latter is not disposed later.
How exactly are you creating invoices each month? Are you using one and the same ObjectSpace for loading multiple reports? If so, would you please provide a small sample project?
Dmirtry,
Thanks for your investigation.
I reviewed your video, what you did is correct. However by creating a snapshot you force the GC to cleanup. When you print multiple invoices you have no idea when the GC joins the show. So the redline in increasing while the printingsystem creates invoices.
I created a video too but want first to know if that make sense…
We create for each invoice an nested objectspace and everything what can be put in usings is used in usings :)
Should it not be more "realistic" to not create snapshots while processing? In that case the GC makes his own decision to clean up, am I right?
Kind regards,
Wim
Perhaps, this problem with the OutOfMemory exception is related directly to the XtraReports product.
I suggest you refer to the following threads:
System.OutOfMemory error is thrown when using a SubReports
XtraReport 'out of memory' error
Load images only for current displayed report page in XtraReport.
Also, this situation often occurs when using XtraReport.FilterString (client filtering) in huge or even large tables:
How to: Filter Data at a Report's Level
Instead, it is necessary to filter data directly by the database:
How to: Filter Data at a Data Source's Level + How to filter data on the server side with XtraReports Parameters
Hi Dmitry,
In the last 3 weeks we investigate our posssible memory leak.
To make smaller steps I created an test application.
I copied our code to the test application and started debugging.
I was be able to reproduce the problem in the simple application.
By implementing the necessary dispose methods and invalidated methods I made big improvements.
Unfortunately it didn't solve the problem.
My conclusion:
- Each Print action (by calling the Print method) will start an new thread! Yes, if I print for example 500 reports, 500 threads will be created. Sometimes this will throws the OutOfMemory exception.
- Back to your video, it was clear. However there is one big issue which is not realistic for our situation. By creating an snapshot, you force GC #0, #1 and #2 to cleanup. The # 2 is the least often throwed to cleanup. So if you run with the profiler, you should wait and the GC #2 should be triggerd by itself. I have seen in the demo application that if I open and close the first report for multiple times, and wait for at least 10 minutes, #2 wont be triggered.
If I watch the information I saw that much instances cant be disposed (For example the XPCollection)
Back to our application: when we print a report, we do the same action as Preview the report, after that we print the report and so on. I already said that each print action creates its own thread. Windows will reserve by default memory for each thread (1MB for 32 bit and 2MB for 64 bit). So when the XafReport cant be disposed, the thread will stay opened and as you can expect, the memory wont be cleaned up.
Kind regards,
Wim
Hello Wim,
Thank you for the update. We will get back to you as soon as we can.
Hello Wim,
You seem to have already created a small example that stably reproduces this behavior. So, would you please send it to us for internal examination? This will allow us to investigate this behavior and provide you with a solution as soon as possible.
I created a small example that prints out a report 500 times (printing to a file), and this scenario works fine for me. It uses only XtraReport. Please find a sample attached to this message.
Hi Dmitry,
Sorry for my delay. I have been on holliday and very busy so want be able to respond earlier.
I watched/investigate your application. Your application makes it already possible to show the problem.
I attached a image with the memory usage. The white line is Live bytes, this are the bytes when garbage #2 collects. The pink line are the bytes in memory which are not collected yet.
From 0 min to 2 min I opened one report, closed and waited. I expect the garbage collector should cleanup so the pink line will fall down to the white line. After that I opend multiple times the preview of the report. You see that the GC is doing a good job and cleanup in peaces and goes back to the beginning.
From 4 minutes I start printing the reports, there you can see the memory is increasing very slow. I should expect that the white line while printing, fall down to the same level as in the beginning.
It could be possible that XAF keep objects reserved so the GC cant cleanup. But back to my previous point.
If I start for example with 5 MB of memory, I open a window, the object(s) will be created, but when I close, this objects are not needed anymore so the memory should decrease back to his previous point, 5 MB.
In the same image I have on the bottom a image of our application. XAF use a LOT memory, we precompile some things in a other thread for faster working. When the graph stops increasing, I printed 20 reports. As you can see the white circles (= point where GC #2 cleaned up) is everything back to the main.
I hope I can make it more clear for you right now, otherwise, just ask :-)
Kind regards,
Wim
Hello Wim,
In fact, it is not guaranteed that the CG will be called automatically after a period of time.
During the normal application life cycle, GC may not be called at all, unless its garbage collection is forced by the CLR.
You can learn more on how the GC works at http://msdn.microsoft.com/en-us/library/ee787088.aspx#conditions_for_a_garbage_collection.
Now please let me elaborate on how we find memory leaks in .NET apps internally.
For example, you may want to check for memory leaks when a report preview is shown.
Here are the steps you would perform:
You can learn more about these steps in the documentation of your preferred memory profiler. For instance, we can also use the .NET Memory Profiler:
http://memprofiler.com/OnlineDocs/default.htm?turl=findmemoryleaks.htm.
At this stage we can analyze the difference between these two snapshots to see whether there are any memory leaks.
In particular, we are looking at the following columns:
Refer to the http://memprofiler.com/OnlineDocs/default.htm?turl=overviewpage.htm help article for more details.
As for the Real-Time Page, it only provides auxiliary or supporting information, and does not allow you to determine a memory leak:
http://memprofiler.com/OnlineDocs/default.htm?turl=realtimepage.htm.
I hope this information helps.