Prism + Telerick = Memory Leak

12 posts, 0 answers
  1. Victor
    Victor avatar
    5 posts
    Member since:
    Feb 2012

    Posted 01 May 2012 Link to this post

    Hello,

    I am using WPF 4.0 and Prism 4.0 with MEF and the latest Radcontrols for WPF. I have 15 core modules containing mostly RadGridViews and RadCharts. These 15 modules are implemented as prism views in a single Window. All modules stay loaded as the application is expected to be long running. Three of the views toggle to a secondary view because I ran out of real estate on the screen. 

    The application is a read only dashboard so I am using MVVM without any command bindings. Viewmodels contain an ObservableCollection of the data class and bind to the Itemsource of the control. All Telerick controls are updating as the data source updates and seem to be operating fine.

    However, I am experiencing a heavy memory leak that is mostly in Telerick code.

    My profiler lists these classes as the highest offenders:
    Telerick.Windows.Data.QueryableCollectionView
    Telerick.Windows.Data.CompositeFilterDescriptorCollection
    Telerick.Windows.Data.SelectDescriptorCollection
    Telerick.Windows.Data.CompositeFilterDescriptor

    Before each update I call Clear() on the ObservableCollection in the Viewmodel but this doesn't seem to help. I derive the Viewmodel from INotifyPropertychanged but it doesn't help and is not needed for update since the ObservableCollection takes care of it. If I raise the property changed event the leak only increases.
     
    I have traced references in my profiler back to the shell and the prism region which live for the lifetime of the application.

    Has anyone experienced this behavior? Are Telerick controls known to leak memory in Prism applications? This must be common scenario for Telerick controls althought I have found little on the web in regards to a Prism memory leak so thought I would post here.

    Thanks in advance for any help.
     Victor
  2. Victor
    Victor avatar
    5 posts
    Member since:
    Feb 2012

    Posted 01 May 2012 Link to this post

    Forgot to add to above post:

    I also see a major memory leak in System.Reflection.Emit with a class called __FixupData[]

    I have no idea what this class is emitting and hope it is not jitting the Telerick controls when they update. Tracing references in my profiler leads back to a regular expression. System.Text.RegularExpressions.Regex and a root of Function.s_typeParser

    Any clues?

  3. UI for WPF is Visual Studio 2017 Ready
  4. Rossen Hristov
    Admin
    Rossen Hristov avatar
    2478 posts

    Posted 01 May 2012 Link to this post

    Hi,

    Someone must be holding onto these objects and not releasing them. Unfortunately, without a runnable sample project which we can run and profile we will not be able to tell who is holding those objects.

    If you can send us a stripped-down dummy version of your project which we can successfully run and profile we might be able to tell what is going on.

    Meanwhile, I am not sure which profiler you are using, but the ANTS one is pretty awesome and can tell much more than WinDbg, i.e. gcroot-ing the offending objects.

    As for the FixupData[] thing, I don't think it is one of our classes.

    Kind regards,
    Ross
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  5. Victor
    Victor avatar
    5 posts
    Member since:
    Feb 2012

    Posted 01 May 2012 Link to this post

    Thanks for your reply Ross.

    I take it there are no known issues with Telerik controls and Prism?

    I am using the ANTS memory profilier. Most objects trace back to the shell (main window) of the application or MEF or a resource. Again, no controls or prism views are released or destroyed. This is a WPF dashboard application meant to be long running. After running for 18 hours I have a 350 MB memory leak. The __FixupData[ ] object seems to be the largest offender and seems to be generating IL for the Telerik.Windows.Data.QueryableCollectionView object in a RadChart in my core module 10. 

    Core 10 is a RadChart with horizontal bars. It displays 10-12 bars at a time when it updates. It's Itemsource is bound to an ObservableCollection of a class that holds it's data objects. On every update cycle I Clear() the collection and then populate with a new set of objects. The RadChart updates itself with these objects. Is it somehow holding on to the previous set of objects? Is there a way to clear it?

    I have attached a PNG of the retention graph from ANTS in hope you can decipher it. This would be the end result of running a sample app, right? I will try to create a sample app but it will be difficult to not include everything in the app. Perhaps you can find a smoking gun in the attachment.

    Thanks again for your attention to this matter.

    Victor
  6. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 04 May 2012 Link to this post

    Hi Victor,

    Thank you for sharing the retention graph!

    As this image shares some light on what is going on, without a runnable sample app that we can debug in our labs, we can only guess what is going on.

    We have developed a completely new charting solution that doesn't use QueryableCollectionView under the hood and is designed with memory and performance in mind. You can try replacing RadChart with RadChartView and profile your application again. I am sure you will be pleased with the performance improvement. You can find information on RadChartView in our online help system here. If you experience a problem in the transition process I will be happy to assist you!

    Regards,
    Yavor
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  7. Efren
    Efren avatar
    3 posts
    Member since:
    May 2012

    Posted 10 May 2012 Link to this post

    Thanks for your response.

    I am unable to refactor my code for the RadChartView at this time since there is no migration path for it. Perhaps in a later version I'll have time in my schedule to do that.

    I did however come up with a solution to stop the memory leak with RadChart and MVVM. I will share this so others in the community can benefit from it.

    In a nutshell, when updating RadChart dynamically from a database or any real time data source, you cannot simply clear your ObservableCollection and refill with new values since RadChart binds to them and never lets go. This was the primary source of the memory leak. Every update cycle I would Clear() the collection in my ViewModel and reload with a new set of data from the Model. In my scenario database tables are cleared each update cycle and all rows are deleted before updating with new data.

    The solution is to reuse items in the ObservableCollection and let the property changed mechanism work. When clearing items in the collection and reloading with new objects, RadChart must re-bind to each new object. This must be the default behavior of the QueryableCollection in RadChart. 

    Here's a code snippet that illustrates it:

    _dc.ocReserve is a List<EntityType> from the EntityFramework. This gets updated in a background thread along with the ViewModel which contains the ObservableCollection n1 that is bound to the RadChart. The trick is to reuse an existing item in the collection instead of clearing it and let the INotifyPropertyChanged mechanism update RadChart from the Model. (Core4Model in this case)

    if (_dc.ocReserve.Count > 0)
    {
        //reuse existing slots in n1
        // n1 is the ObservableCollection
        foreach (ReservationEntity x in _dc.ocReserve)
        {
            if (n1.Count > 0 && y < n1.Count)
            {
                n1[y].PartySize = x.PartySize;
                n1[y++].ReservationTime = x.ReservationTime;
            }           
             // or create a new one
            else if (_dc.ocReserve.Count > n1.Count)
            {
                Core4Model m = new Core4Model();
                m.PartySize = x.PartySize;
                m.ReservationTime = x.ReservationTime;
                n1.Add(m);
                y++;
            }
        }
     
        // if we have less items in the source than the collection let's remove the old ones
        if (_dc.ocReserve.Count < n1.Count)
        {
            for (int i = n1.Count - _dc.ocReserve.Count; i != 0; i--)
            {
                n1.RemoveAt((y - 1) + i);
            }
        }
    }
    else
         //in the event there is nothing in the database go ahead and clear it 
        n1.Clear();

    This simple reuse pattern has eliminated the leak. Luckily in my case database rows tend to grow and not shrink because any shrinkage will still cause a small memory leak.

    Again, this is a workaround for using RadChart with dynamic updates and MVVM. BTW, the latest Telerik Visual Studio add-in I used dropped the RadChart on my page right out of the gate. Perhaps you should consider switching to the RadChartView since this is what you recommend moving forward.

    Victor G.  
  8. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 15 May 2012 Link to this post

    Hi Victor,

    Thank you for your detailed inside! I will forward it to our development team for consideration.

    All the best,
    Yavor
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  9. Mark
    Mark avatar
    15 posts
    Member since:
    Jan 2013

    Posted 17 Jan 2013 Link to this post

    Regarding repopulating the ObservableCollection: I have a question about the DataLoaded event and knowing then the collection is actually finished loading.

    Case 1) When repopulating the list, with each item individually, the DataLoaded event gets called multiple times.

    Case 2) When using:
      myViewer.ItemsSource = myObservableCollection
    the DataLoaded event only gets called when all items are loaded.

    So, if I am repopulating the list (the solution recommended here), is there a way to know when the last item is loaded?

    Thank you
    Mark

  10. Ves
    Admin
    Ves avatar
    2879 posts

    Posted 22 Jan 2013 Link to this post

    Hi Mark,

    I am not sure I followed you completely. Is RadGridView involved here?

    As a general advice -- you can use Telerik.Windows.Data.RadObservableCollection -- it exposes API to suspend and resume change notifications, so you get only a single CollectionChanged event. Here is an example:

    Telerik.Windows.Data.RadObservableCollection<int> myCollection = new Telerik.Windows.Data.RadObservableCollection<int>();
     myCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(a_CollectionChanged);
     myCollection.SuspendNotifications();
     myCollection.Add(5);
     myCollection.Add(5);
     myCollection.ResumeNotifications();
    .......
     
    void a_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                // This is executed just once.
            }


    Best regards,
    Ves
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  11. Mark
    Mark avatar
    15 posts
    Member since:
    Jan 2013

    Posted 22 Jan 2013 Link to this post

    Hmmm.. .I did not now about RadObservableCollections.

    Yes RadGridView is involved. I want to assign new items to the ItemsSource.

    This, and other, posts suggest (to reduce memory leaks) that it is not a good idea to simply assigning a new collection, instead they suggest to reuse the same collection.
    ie. 
    1) // Memory Leak way
      myGridView.ItemsSource = collectionData;   // previously assigned collection of data is not cleaned up properly

    2) // Better way (reuse the collection)
    // setup
      myDataCollection = new ObservableCollection();
      myGridView.ItemsSource = myDataCollection;

    // later, when new data is available
    myDataCollection.Clear()
    myDataCollection.Add(item)
    etc.

    However, the advantage of the case 1) was that the GridView.DataLoaded is only called once. That way, I can know when all the data is finished loading. Method 2) above will cause the DataLoaded method to be called after every item is added.

    If I use the RadObservableCollection and Suspend notifications while I am loading (and resume them when it is finished), will that cause the GridView.DataLoaded method to only be called once (when it is finished)?

    Thank you for your help and patience with my explanations :-)
  12. Ves
    Admin
    Ves avatar
    2879 posts

    Posted 25 Jan 2013 Link to this post

    Hi Mark,

    That's correct. Using the approach shown in the code snippet in my previous message DataLoaded event will be triggered just once. In fact -- this will happen within ResumeNotifications method.

    Best regards,
    Ves
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  13. Mark
    Mark avatar
    15 posts
    Member since:
    Jan 2013

    Posted 29 Jan 2013 Link to this post

    Great, thank you for your help.
Back to Top
UI for WPF is Visual Studio 2017 Ready