lead while refreshing grid

Use this forum for questions on how to use .NET Memory Profiler and how to analyse memory usage.
Post Reply
stijn
Posts: 23
Joined: Thu Jun 28, 2007 2:57 pm

lead while refreshing grid

Post by stijn » Fri Aug 29, 2008 1:07 pm

In my application I have an inbox like window, containing a datagridview, feeded by a dataset,
after each refresh (manual by button click in this case)
There appear hundred new datagridrow instances and a thousand more datagridviewtextboxcell instances, while there dont appear any disposed or removed ones .

This accounts to a 500 MB memory leak, if the application is kept running for more then 20 hours (with autorefresh every minute)
see rootpath and callstack :

when the window gets closed (and the datagridview disposed) , the memory is released


DataGridViewRow.Clone()
DataGridViewRowCollection.get_Item(int)
DataGridView.OnClearingRows()
DataGridViewRowCollection.ClearInternal(bool)
DataGridView.RefreshRows(bool)
DataGridView.DataGridViewDataConnection.ProcessListChanged(ListChangedEventArgs)
DataGridView.DataGridViewDataConnection.currencyManager_ListChanged(object, ListChangedEventArgs)
CurrencyManager.OnListChanged(ListChangedEventArgs)
CurrencyManager.List_ListChanged(object, ListChangedEventArgs)
BindingSource.OnListChanged(ListChangedEventArgs)
BindingSource.InnerList_ListChanged(object, ListChangedEventArgs)
DataView.OnListChanged(ListChangedEventArgs)
DataView.UpdateIndex(bool, bool)
DataView.UpdateIndex(bool)
DataView.SetIndex2(string, DataViewRowState, IFilter, bool)
DataView.SetIndex(string, DataViewRowState, IFilter)
DataView.set_RowFilter(string)
DataView.System.ComponentModel.IBindingListView.set_Filter(string)
BindingSource.set_InnerListFilter(string)
BindingSource.SetList(IList, bool, bool)
BindingSource.ResetList()
BindingSource.set_DataSource(object)
vwMyFlow.FetchFlow()
vwMyFlow.toolStripBtnRefresh_Click(object, EventArgs)
ToolStripItem.RaiseEvent(object, EventArgs)
ToolStripItem.OnClick(EventArgs)
ToolStripButton.OnClick(EventArgs)
ToolStripItem.HandleClick(EventArgs)
ToolStripItem.HandleMouseUp(MouseEventArgs)
ToolStripItem.FireEventInteractive(EventArgs, ToolStripItemEventType)
ToolStripItem.FireEvent(EventArgs, ToolStripItemEventType)
ToolStrip.OnMouseUp(MouseEventArgs)
Control.WmMouseUp(Message&, MouseButtons, int)
Control.WndProc(Message&)
ScrollableControl.WndProc(Message&)
ToolStrip.WndProc(Message&)
Control.ControlNativeWindow.OnMessage(Message&)
Control.ControlNativeWindow.WndProc(Message&)
NativeWindow.Callback(IntPtr, int, IntPtr, IntPtr)
[Unmanaged to managed transition]
[Managed to unmanaged transition]
UnsafeNativeMethods.DispatchMessageW(NativeMethods.MSG&)
Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int, int, int)
Application.ThreadContext.RunMessageLoopInner(int, ApplicationContext)
Application.ThreadContext.RunMessageLoop(int, ApplicationContext)
Application.Run(ApplicationContext)
AppContext.Main()


System.Windows.Forms DataGridViewRow
System.Windows.Forms DataGridViewComboBoxCell
System EventHandler
System Object[]
System EventHandler
System.ComponentModel EventHandlerList.ListEntry
System.ComponentModel EventHandlerList
System.Windows.Forms BindingSource
System.Windows.Forms PropertyStore.ObjectEntry[]
System.Windows.Forms PropertyStore
System.Windows.Forms DataGridViewComboBoxCell
System.Windows.Forms DataGridViewComboBoxColumn
DIASUI.FlowUI vwMyFlow
DIASUI frmMain
System.Windows.Forms Application.ThreadContext
System.Windows.Forms Application.ComponentManager System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int, int, int)

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Fri Aug 29, 2008 2:01 pm

I have taken a quick look at the DataGridView. When the underlying datasource changes (ListChanged), the RefreshRows method gets called, which in turn clears the rows in the grid view. It seems like when the DataGridViewRowCollection gets cleared, it will recreate a set of new (empty?) DataGridViewRows for each visible row. These new rows are unshared rows which are cloned based on template cells. When a new DataGridViewComboBoxCell gets created, the Datasource is assigned and the cell adds an event handler to the DataSource. However, this event handler will not be removed when clearing the rows and thus the DataGridViewComboBoxCells will never be GCed.

I have not worked much with the DataGridView, so I will need some more time to investigate this before I can come up with a good explanation of the problem and hopefully a workaround.
Best regards,

Andreas Suurkuusk
SciTech Software AB

stijn
Posts: 23
Joined: Thu Jun 28, 2007 2:57 pm

Post by stijn » Mon Sep 01, 2008 10:05 am

Indeed,
when we replace all our comboboxcolumns by textboxcolumns the problem does not occur.

If you can find a better workaround, please let us know

Thx

Andreas Suurkuusk
Posts: 1029
Joined: Wed Mar 02, 2005 7:53 pm

Post by Andreas Suurkuusk » Thu Sep 04, 2008 9:38 am

I've been trying to find a good work-around for this leak, but I have not been able to find a reasonably simple one.

One work-around that exists, is to not use a DataSource that implements IComponent (or ISupportInitializeNotification) for the combobox column items. This will prevent event handlers from being added, and no memory leak will occur. Is is possible for you to use a simple DataSource, such as List<T>, instead of something like DataTable or DataView? If you can, I think you will be able avoid the memory leak.
Best regards,

Andreas Suurkuusk
SciTech Software AB

stijn
Posts: 23
Joined: Thu Jun 28, 2007 2:57 pm

Post by stijn » Sat Sep 13, 2008 1:01 pm

It would be possible to convert all tables into lists as well,
thx

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 26 guests