This is a migrated thread and some comments may be shown as answers.

Free-ing Memory when disposing GridView

9 Answers 1073 Views
GridView
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Antoine
Top achievements
Rank 1
Antoine asked on 29 May 2009, 10:48 AM
Hi,

I have attached a RadDocking control in my application where i dynamically load panes (which contain RadGridView objects) inside the document host group. 

When i try to remove panes from the document host group, i do the following
  • Remove all event subscription on the custom usercontrol
  • Call the Dispose function on the custom usercontrol (it implements the IDisposable interface)
  • Set Content property of the pane to null
  • Remove the pane from the document host group
  • Call the Garbage Collector GC.Collect()

The Dispose function on the custom usercontrol does the following
  • Remove all event subscription on all objects inside the usercontrol
  • Remove all items from grid
  • Set grid's ItemsSource to null
  • Remove all objects from the master grid (LayoutRoot.Children.Clear())

Although i am doing all these things, the pane is properly removed from the docking control but the Memory Usage i see on the task manager does not fall although i call the garbage collector. 

Example. 
  1. Initial state - Memory Usage: 85Mb
  2. Application loads Docking control and custom control (with gridview inside) - Memory Usage: 105Mb
  3. Custom UserControl asks for data from a WCF Service. Get's Data and binds them to GridView - Memory Usage: 130Mb
  4. User does custom action and the Pane has to be removed. Pane is removed, following the procedure described above - Memory Usage - 130Mb
  5. If the user loads the UserControl again, the memory usage will again be increased by 25Mb approximately. 

Can you help me on that, because if the user closes and opens several panes (and usercontrols) memory usage is up to 250Mb and more!

Thanks,

Antonis

9 Answers, 1 is accepted

Sort by
0
Hristo Deshev
Telerik team
answered on 30 May 2009, 11:22 AM
Hello Antoine,

Looking at your description, the cleanup procedures seem OK, but it can be hard to make sure you have detached all events and object references. Does the problem occur if you temporarily replace RadGridView with another control, say a vanilla ItemsControl?

Such issues are hard to troubleshoot without having a reproduction project at your fingertips. I would appreciate you helping me reproduce the problem on my end, so that I can provide more specific advice.

Greetings,
Hristo Deshev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Antoine
Top achievements
Rank 1
answered on 02 Jun 2009, 01:06 PM
I think i found the problem.

It seems that when i have a RadGroupDescription attached on my RadGridView there is a memory leak. 

I noticed small memory leaks (2-3Mb approximatelly) when i have a large datasource and don't have a GroupDescription on my GridView. Though when i have two GroupDescriptions on my GridView and try to reload data 3-4 times the memory of my application goes up 20-30mb at each reload, that means 80Mb+ for 4 reloads.

The Xaml of my UserControl is:

<UserControl x:Class="MemoryTest.Page" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    xmlns:grid="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"         
    xmlns:data="clr-namespace:Telerik.Windows.Data;assembly=Telerik.Windows.Data"              
    xmlns:y="clr-namespace:MemoryTest"
     
    <Grid x:Name="LayoutRoot" Background="White"
        <Grid.RowDefinitions> 
            <RowDefinition Height="30"/> 
            <RowDefinition Height="*"/> 
        </Grid.RowDefinitions> 
         
        <StackPanel Grid.Row="0"
            <Button Content="Reload" Click="Button_Click"/> 
        </StackPanel> 
 
        <grid:RadGridView Grid.Row="1" x:Name="grid" > 
            <grid:RadGridView.GroupDescriptions> 
                <data:RadGroupDescription PropertyName="Column_1" SortDirection="Ascending"/> 
                <data:RadGroupDescription PropertyName="Column_2" SortDirection="Ascending"/> 
            </grid:RadGridView.GroupDescriptions> 
        </grid:RadGridView> 
    </Grid> 
</UserControl> 


The codebehind of this class is:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 
using Telerik.Windows.Data; 
using Telerik.Windows.Controls; 
using Telerik.Windows.Controls.GridView; 
 
namespace MemoryTest 
    public partial class Page : UserControl 
    { 
        public Page() 
        { 
            InitializeComponent(); 
        } 
 
        private void Button_Click(object sender, RoutedEventArgs e) 
        { 
            this.grid.ItemsSource = null
            this.grid.ItemsSource = Person.GeneratePersonList(); 
 
            GC.Collect(); 
            GC.WaitForPendingFinalizers(); 
            GC.Collect(); 
        } 
    } 
 



The class i am using as a datasource is the one below:

    public class Person : INotifyPropertyChanged 
    { 
        public static IList<Person> GeneratePersonList() 
        { 
            IList<Person> persons = new ObservableCollection<Person>(); 
             
            for (int i = 0; i <= 1000; i++) 
            { 
                Random rnd = new Random(); 
 
                persons.Add(new Person() 
                { 
 
                    column_1 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_2 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_3 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_4 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_5 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_6 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_7 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_8 = String.Format("{0}", rnd.NextDouble() * 100000.00), 
                    column_9 = String.Format("{0}", rnd.NextDouble() * 100000.00) 
                } 
                ); 
            } 
 
            return persons; 
        } 
 
        private String column_1; 
 
        public String Column_1 
        { 
            get { return column_1; } 
            set { column_1 = value; 
            OnPropertyChanged("Column_1"); 
            } 
        } 
 
        private String column_2; 
 
        public String Column_2 
        { 
            get { return column_2; } 
            set { column_2 = value; OnPropertyChanged("Column_2"); } 
        } 
        private String column_3; 
 
        public String Column_3 
        { 
            get { return column_3; } 
            set { column_3 = value; OnPropertyChanged("Column_3"); } 
        } 
        private String column_4; 
 
        public String Column_4 
        { 
            get { return column_4; } 
            set { column_4 = value; OnPropertyChanged("Column_4"); } 
        } 
        private String column_5; 
 
        public String Column_5 
        { 
            get { return column_5; } 
            set { column_5 = value; OnPropertyChanged("Column_5"); } 
        } 
        private String column_6; 
 
        public String Column_6 
        { 
            get { return column_6; } 
            set { column_6 = value; OnPropertyChanged("Column_6"); } 
        } 
        private String column_7; 
 
        public String Column_7 
        { 
            get { return column_7; } 
            set { column_7 = value; OnPropertyChanged("Column_7"); } 
        } 
        private String column_8; 
 
        public String Column_8 
        { 
            get { return column_8; } 
            set { column_8 = value; OnPropertyChanged("Column_8"); } 
        } 
        private String column_9; 
 
        public String Column_9 
        { 
            get { return column_9; } 
            set { column_9 = value; OnPropertyChanged("Column_9"); } 
        } 
 
        protected virtual void OnPropertyChanged(String propertyName) 
        { 
            if (String.IsNullOrEmpty(propertyName)) 
            { 
                return
            } 
            if (PropertyChanged != null
            { 
                PropertyChanged(thisnew PropertyChangedEventArgs(propertyName)); 
            } 
        } 
 
        public event PropertyChangedEventHandler PropertyChanged; 
 
 
    } 




I also tried removing all GroupDescriptions by code (on the reload event) and add them again but still had no luck:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 
using Telerik.Windows.Data; 
using Telerik.Windows.Controls; 
using Telerik.Windows.Controls.GridView; 
 
namespace MemoryTest 
    public partial class Page : UserControl 
    { 
        public Page() 
        { 
            InitializeComponent(); 
 
        } 
 
        private void Button_Click(object sender, RoutedEventArgs e) 
        { 
 
            this.grid.ItemsSource = null
            this.grid.ItemsSource = Person.GeneratePersonList(); 
             
            this.grid.GroupDescriptions.Clear(); 
            this.grid.GroupDescriptions.Add(new RadGroupDescription("Column_1""Column_1")); 
            this.grid.GroupDescriptions.Add(new RadGroupDescription("Column_2""Column_2")); 
 
            GC.Collect(); 
            GC.WaitForPendingFinalizers(); 
            GC.Collect(); 
        } 
    } 
 


Many thanks, 

Antonis
0
Hristo Deshev
Telerik team
answered on 03 Jun 2009, 03:29 PM
Hi Antoine,

Thanks for the detailed report! I managed to reproduce the memory leak. It turned out that when grouping, each group's virtualization panel leaks because of a strong reference that it holds to its parent. We got that fixed and I can arrange that you get an unofficial build -- just open up a separate support ticket to request that.

Oh, and I have updated your Telerik points.

Sincerely yours,
Hristo Deshev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Antoine
Top achievements
Rank 1
answered on 03 Jun 2009, 04:14 PM
Many thanks for the quick response!

I am glad you found the leak! Anything we can do to help you build great components!:)

You still got to sort out the small memory leaks though. Even if you don't have a GroupDescription attached on your grid there are small leaks. You can see this on the task manager if you bind data to the GridView several times.

You can use the example i have above but remove the GroupDescriptions. 

The application starts with 64Mb.
1. By binding the data once, it goes up to 84Mb.
2. Doing the same thing one more time you can see on the task manager that memory goes down to 81 instantly (like clearing memory) and then up to 86Mb.
3. Doing the same thing one more time task manager shows 89Mb.
4. Doing the same thing one more time task manager shows 92Mb.
5. Doing the same thing one more time task manager shows 94Mb.
6. Doing the same thing one more time task manager shows 97Mb.

So you can understand that its time i call my application to get me the same data and bind them to the GridView, memory usage of the application goes up by a step of 2-3Mb.

I can't open a support ticket unfortunately since my company doesn't have a telerik subscription so we are using the trial version. We are planning buying them when we finish developing the biggest part of our silverlight application. So i'll have to wait for the official internal build! 


Many thanks,

Antonis






0
Hristo Deshev
Telerik team
answered on 04 Jun 2009, 03:26 PM
Hi Antoine,

I've slain another memory leak today, and that makes it three total since your report. We are continuing our work on the smaller leaks. I guess you can try the internal build that we'll upload tomorrow, and see how it goes.

Sincerely yours,
Hristo Deshev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Antoine
Top achievements
Rank 1
answered on 04 Jun 2009, 04:45 PM
Great news Hristo,

I will wait for the internal build and tell you how it goes


Thanks for the fast feedback!

Antonis
0
Antoine
Top achievements
Rank 1
answered on 09 Jun 2009, 07:38 AM
Hristo,

I replaced my project's references to the new Telerik Components (2009.1.605.1020) but i still have memory leaks. 

The small memory leaks i mentioned did not dissapear. Grouping still has big memory leaks (not that big as in the beggining but quite big). Also i noticed that there is a big memory leak when you move and generally change position of columns. 

You can still use the example i have on this thread which is quite simple and you will see that after some rebinding you will get a big memory usage for your application. 

The thing with the grouping and moving columns is crucial cause users tend to change appearance very often and play with the grid!

Also you can navigate on your online demo. If you go to the performance section that you bind 1 million records and then go elsewhere you can see on the task manager that memory is up by 150Mb. If you go back to the 1 million records example memory increases again by 150Mb!!!! If you do that several times you can crash your browser. (I know that it's the non-internal build version but as i said you can try it the small example i have posted and you can get the same results)

Personally, i think that you have built some great components but memory leaks is something you should work on and be very careful. Silverlight is a very neat platform to work on but since all applications are browser based you want to have it as light as it can be!


Many thanks, 

Antonis

0
Hristo Deshev
Telerik team
answered on 11 Jun 2009, 07:27 AM
Hi Antoine,

We are working on eliminating leaks as we find those. We are aware of the smaller memory leaks and plan on addressing those too -- we just could not do it for that internal build.

We are doing some significant rework on our data engine at the moment, and I think that will eliminate a big portion of the leaks because we are intentionally avoiding the use of several leak-dangerous coding patterns.

Sincerely yours,
Hristo Deshev
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Antoine
Top achievements
Rank 1
answered on 11 Jun 2009, 07:32 AM
Many thanks Hristo,

will wait for your work!
Tags
GridView
Asked by
Antoine
Top achievements
Rank 1
Answers by
Hristo Deshev
Telerik team
Antoine
Top achievements
Rank 1
Share this question
or