Memory Usage in Reporting - Best Practices
- 9 minutes to read
This help topic includes tips on memory usage optimization and explains how you can prevent common reporting-related memory consumption issues.
This topic describes three main issues related to memory consumption:
- Reporting components consume too much memory
- Memory usage continues to rise
- The `OutOfMemory` exception is thrown
Reporting Components Consume Too Much Memory
Common Tips
Dependencies
Due to .NET specifics, all dependent assemblies are loaded to the application’s memory on demand. As a result, the first time you run a report in your application you may observe an increase in memory usage. This is expected behavior.
DevExpress and third-party library versions
Recent versions (the latest minor build for the last three major versions) of DevExpress components can optimize performance and memory use compared to older releases.
The same relates to third-party libraries (for example, Skia) that may be required by our components on non-windows platforms.
How to reduce memory consumption:
- Use the newest major version of DevExpress components that is available to you.
- If you use an older major version of DevExpress components, make sure that you update to the latest minor build released for this version.
- If you use our components on non-windows platforms, use the newest stable versions of third-party libraries that are required for our components to run on this platform.
Content volume / number of pages in reports
The more pages a report document contains, the more memory is required to store this document.
How to reduce memory consumption:
- Use the CachedReportSource component to enable document caching. It is possible to cache a report’s document pages to the file system or a database to reduce memory usage even further.
- Reduce the amount of information displayed in your report to decrease the number of pages in the exported or previewed document. For example, use the report’s Filtering and Parameters functionality to allow users to choose what information should be displayed in the report.
- Filter data at the data source level if the report’s data source supports it. This will help reduce the amount of data stored within the report’s data source after it is filled with data and will increase the report loading speed.
Report Controls
XRPictureBox controls
Raster images loaded to XRPictureBox controls are stored in report documents as bitmaps. The larger the image’s dimensions, the more memory is consumed.
How to reduce memory consumption:
- Reduce dimensions of raster images loaded to
XRPictureBox
controls. - If you display repeated images in your document, use the ImageUrl property to assign images to the
XRPictureBox
control. A report can cache images with the sameImageUrl
values if it uses the CachedReportSource component.
XRRichText Controls
The XRRichText
control uses the functionality of DevExpress Word Processing Document API. For each individual control, the report creates a rich document model. This is a very resource-intensive operation. As a result, a report with XRRichText
controls may consume lots of memory.
How to reduce memory consumption:
- Replace
XRRichText
controls with XRLabel controls. You can enable AllowMarkupText functionality in theXRLabel
control to add simple formatting to text.
Web Reporting Components
The Web Document Viewer component and the Web Report Designer’s preview functionality use the in-memory cache to store previewed documents. As a result, the application usage may grow each time a report preview is executed in a web application, and the memory may not be released immediately after the preview is closed. Check the Document Viewer Lifecycle documentation for more details on how this works.
It is not possible to completely disable the in-memory cache while using these components due to architecture specifics.
Note
This behavior does not relate to Report Viewer for Blazor (Native) and is specific to JavaScript-Based Blazor Reporting controls.
How to reduce memory consumption:
- Enable the UseCachedReportSourceBuilder mode.
- Enable file system storage for the document preview control. In .NET 6+ applications, you can also use
IDistributedCache
as a storage. Close the previewed document each time before the browser’s page is closed to release the previewed document immediately.
Note
Document viewers for Angular and Blazor platforms release previewed documents automatically.
Use StorageCleanerSettings and CacheCleanerSettings services to configure document and report lifetimes in Document Viewer’s storage and in-memory cache.
All of these recommendations are demonstrated in the following code example: ASP.NET Core Reporting Best Practices.
Alternative Report Preview Methods
If none of the recommendations listed above help and you wish to reduce your web application’s memory usage as much as possible, you can replace a Document Preview in your web application with an exported PDF document. For example, you can use the <embed>
HTML tag. Check the following help topic to learn how to export a report to PDF in a web application: Export Without a Preview.
You can use an external Parameters Panel control to pass parameters to a report while using this solution.
In the server-side code, you can also use either CachedReportSource or PdfStreamingExporter components to generate a PDF document. These components allow you to try different export algorithms and choose which one is best for your particular report, according to your export performance and memory consumption requirements.
Memory Usage Continues to Rise
The following sections explain how to diagnose a possible memory leak.
Confirm a Memory Leak
Due to .NET application architecture specifics, an increase in memory usage does not always indicate a memory leak. In most cases, this is related to .NET garbage collection specifics.
To confirm a memory leak, check if the application’s memory is released after garbage collection.
To trigger garbage collection in your application, you can use .NET memory profiling tools or call the following code in your application:
GC.Collect();
GC.WaitForPendingFinalizers();
Proceed to the next step only if the memory is not cleared after several garbage collections.
Analyze Memory Usage
Use .NET memory profiling tools to analyze your application’s memory usage.
The following example shows how you can diagnose a memory leak with a standard dotnet-gcdump tool. Similar steps can be used with any other .NET memory profiling tool.
- Run the reporting application.
- Open/preview a report in your application for the first time to load all dependencies and static resources.
Wait until the memory used by the report is released.
If you use the
Web Document Viewer
orWeb Report Designer
component, make sure that the document was cleared from in-memory storages and caches. The report document’s default lifetime is 2 minutes in an in-memory cache and 2 hours in an in-memory storage. These durations can be configured by cache and storage cleaner services.Finally, make sure that the garbage collection was finished after a report and its document were disposed of in your application.
Collect the initial memory dump. For this, use the
collect
command available indotnet-gcdump
.- Replicate the memory leak issue. Follow the steps required to replicate a memory leak with your reports. For example, you can run the same report multiple times.
- Wait until the memory used by reports is released (repeat step three).
- Collect the final memory dump.
Compare collected memory dumps.
To analyze memory dumps generated by dotnet-gcdump, you can use the Visual Studio IDE. Open the final memory dump in Visual Studio, select the initial memory dump as a baseline, and sort data types by size:
See the following help topic for more information: Debug a memory leak in .NET.
Review the following tutorials for more information on how to analyze an application’s memory usage with cloud services:
Solve the Memory Usage Issue
Analyze memory dumps by reviewing what types are leaking. If you see no DevExpress types in the list of leaking types, the issue is most likely not related to our components.
The general recommendation for this step is to review how problematic objects were created in your application, and then make sure that all of these objects are disposed of correctly in your code.
If you are sure that your code is correct, but you see leaking DevExpress objects in your application, report the memory leak to DevExpress Support.
The OutOfMemory Exception is Thrown
The OutOfMemory
exception indicates that there is not enough memory in your application to continue the code execution.
In most cases, this exception does not indicate bugs and memory leaks. The following solutions are available:
Reduce memory consumption.
To reduce the amount of memory consumed by Reporting components, follow recommendations listed in the Reporting Components Consume Too Much Memory in an Application section in this help topic. Use a memory profiler to check if other parts of your application consume large amounts of memory.
Increase the amount of memory available for your application.
This step is mainly relevant for x86 applications that use 32-bit architecture. Such applications are limited by only 2 GB of memory on Windows, even if more memory is available on the machine. Therefore, migrating to the x64 platform may resolve the exception.
If none of these recommendations help, follow recommendations listed in the Analyze the Memory Usage section in this help topic to diagnose a possible memory leak.
Report Memory Leaks to DevExpress Support
Before you start, please follow the diagnostic steps described above to confirm the memory leak and to make sure that this leak is related to DevExpress components.
To report the issue, submit a new support ticket and specify the following information:
Platforms and frameworks.
Specify the platform you are developing for: ASP.NET Core, Angular, Blazor, or other. Specify the version of .NET that you use.
Environment information.
Specify the operating system where the problem occurs. For web applications, check information related to the hosting environment. Clarify if you use any additional tools (for example, Docker) and specify their configurations.
DevExpress components information.
List DevExpress components you use in your application and their versions.
Steps to reproduce the issue in your application.
List the steps required to reproduce the issue. Describe how our components are used and how much data is loaded to them.
Share implementation details.
Send us the code you use to configure and run our components in your application. If the issue occurs with specific reports, share the source code of the problematic reports or layouts with us. Alternatively, reproduce the problem in a simple demo project with dummy data that you can send to us for investigation.
Attach information obtained after conducting memory usage diagnostics.
Share the results of following the diagnostic steps described above.