Skip to Content
0

WPF Viewer memory leak in ReportAlbum

Aug 15, 2017 at 11:17 AM

91

avatar image
Former Member

Hello,

ReportAlbum instance is held by CommandManager and it cannot be collected by GC. See screenshot from .NET Memory Profiler.

I've analysed that the problem is ReportAlbum constructor that adds CommandBinding throught RegisterClassCommandBinding into CommandManager and passes instance method TabCloseExecuted.

Screenshot from .NET Memory Profiler

10 |10000 characters needed characters left characters exceeded
* Please Login or Register to Answer, Follow or Comment.

4 Answers

Best Answer
Don Williams
Aug 18, 2017 at 02:03 PM
0

Cool,

Just be aware if you run into resource issues I won't be able to escalate to DEV.

Also, I just escalated possibly a similar issue to DEV also, CPU seems to consume 1 ->5 % when the report is loaded, may be the same animation causing the problem.

Set for SP 22.

Don

Share
10 |10000 characters needed characters left characters exceeded
Don Williams
Aug 15, 2017 at 08:45 PM
0

Where does it show that it's the WPF viewer that is the cause of the leak?

How much of a leak are you seeing?

Have you ruled out all of Microsoft's dll's don't leak?

Show 1 Share
10 |10000 characters needed characters left characters exceeded
Former Member

Here is example:

<!-- MainWindow.xaml -->
<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="OpenCrystal" Click="Button_Click" />
    </Grid>
</Window>

/* MainWindow.xaml.cs */
using System;
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 1000; i++)
            {
                var wnd = new CrystalReportsWindow();
                wnd.Show();
                wnd.Close();
            }
        }
    }
}

<!-- CrystalReportsWindow.xaml -->
<Window 
    x:Class="WpfApp2.CrystalReportsWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:crview="clr-namespace:SAPBusinessObjects.WPF.Viewer;assembly=SAPBusinessObjects.WPF.Viewer"
    Title="CrystalReportsWindow" Height="600" Width="800">
    <crview:CrystalReportsViewer x:Name="crystalReportsViewer" />
</Window>

/* CrystalReportsWindow.xaml.cs */
using System;
using System.Windows;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for CrystalReportsWindow.xaml
    /// </summary>
    public partial class CrystalReportsWindow : Window
    {
        public CrystalReportsWindow()
        {
            InitializeComponent();
        }
    }
}


The leak is everytime the SAPBusinessObjects.WPF.Viewer.CrystalReportsViewer is created. It prevents the closed CrystalReportsWindow to be collected.

The ReportAlbum instances are held by CommandManager.

After 1000 crystal reports viewer windows shown&closed this simple example takes 789464 KB of memory.

0
Don Williams
Aug 16, 2017 at 05:00 PM
0

Hi Tomas,

So all you are doing is loading 1000 instances of the WPF viewer... WHY, makes no sense to do that, you cannot load 1000 reports, engine won't allow it, 3 max.

Load a report, when done close the report and load a new one in the same instance of the viewer. The single instance leaks 316 bytes, nothing to be concerned about.

Don

Show 1 Share
10 |10000 characters needed characters left characters exceeded
Former Member

Hi Don,

The engine allows me to have multiple viewers in same time. There is no limit.

We have users that browse many reports during a day and they require to see them in one time.

The leak is bigger because the CrystalReportsViewer is placed on a Window. This window contains more UI controls than single CrystalReportsViewer. Plus ViewModels...

Tomas

0
Don Williams
Aug 17, 2017 at 01:25 PM
0

The CR Engine will only allow 3 reports to be processed at any one instance, it will work up to 75 ish because not all reports are executed at the exact same time. So depending on the report load you may be able to possible get 75 jobs running at one time.

For high Report processing applications this is not the right way to use it. You will run into all sorts of resource issues and nothing we can do about it, it's by design.

CR for VS simply was not designed nor is it capable to be used in a high work load environment.

All I can suggest then is possibly don't use the WPF viewer and use the CR Windows Form viewer, it may help.

What you really need to use is CR Server or the full BOE Servers that can handle 1000's of reports in any given time depending on licensing and other options, assuming you give it enough resources and add multiple Report Servers you will be able to manage multiple reports.

Be aware each users instance of a report consumes one license.

Here's a link for more info in CR Server:

https://www.sap.com/products/crystal-server.html

It's a simplified version of the full BOE Product, limited to one PC but can have up to 4 Report Application Servers on it. RAS is running as a service and not an inproc version you may be/are using.

Don

Show 1 Share
10 |10000 characters needed characters left characters exceeded
Former Member

Hi Don,

Thanks for your explanation. I've tested that up to 75 viewers can be used in one time.

I've created a workaround that removes the CommandBinding from CommandManager through reflection and the WPF viewer is fine now with memory.

Tomas

0