views:

70

answers:

2

I have a DataGridView being regularly populated via data-bound objects, and the number of rows can potentially become large, say many thousands during a 'logging cycle'.

When a new 'logging cycle' begins, the grid is cleared because the underlying datasource is cleared and the process begins again.

This is all fine, but because the previous run takes some time, all those previous rows have become Generation 2 objects, and only garbage collected on a full GC.

However, it takes TWO full GC's to clear them out because the first one sends them all to the finalizer queue. This means that they hang around twice as long hogging memory.

Using reflector, I see that DataGridViewRow does not have a finalizer method, but it does inherit from a DataGridViewBand object, which does - and it calls GC.SuppressFinalize(this) via it's public Dispose() method.

So my question is - why do my DataGridViewRows not get collected on the first full GC and make it onto the finalizer queue awaiting another one?

(My assumptions here are that any object without a finalizer should not get placed onto the finalizer queue, and any object that does have one but calls GC.SuppressFinalize will also not be placed on the queueo. Am I right in this assumption?)

Thanks.

A: 

If you don't dispose your objects, then they will not have finalisation suppressed.

Drew Noakes
I agree, but I don't directly create the rows, they are created by data binding. Do I still have to call dispose on them somehow?
Andy
+1  A: 

The call to GC.SuppressFinalize(this) essentially tells the GC that the cleanup behaviors that occur during finalization have already happened (via the call to Dispose()) and that it doesn't need to perform the finalization again. This has no bearing on whether or not the object is placed on the finalization queue.

Any time a finalizable object is instantiated (newed), it is placed on the finalization queue. The finalization queue is only processed during every full GC collection (Gen2 collection). One of the problems with finalizable objects is that they will survive at least one extra GC cycle before they are actually collected.

Scott Dorman
Thanks Scott, so it appears my understanding is somewhat flawed? The fact that a row inherits from an object with a Finalize method means it will always be placed on the queue and subject to the double GC to clear it, and what I am seeing is correct? Ouch!
Andy
@Andy: Yes, your understanding was incorrect. Since `DataGridViewRow` inherits from a finalizable object, it effectively becomes a finalizable object as well and is placed on the queue. What you are seeing is correct. Most likely the `Clear()` method does not also dispose of the rows, in which case you could manually dispose of them prior (or after) calling `Clear()` although I'm not certain if that will be possible. (It will depend on how things are implemented.) Optionally, you might be able to call `Dispose()` on the underlying datasource, which *might* work as well.
Scott Dorman
Hmmm, interesting. I have tried calling Clear(), but I get errors because I 'Can't clear a databound grid', essentially because the databinding takes care of populating / depopulating which seems fair enough. Hadn't thought of calling dispose on the datasource though, will give it a go.
Andy
Didn't appear to do anything, so I think it's the way it has to be.
Andy
@Andy: I suspected that disposing the underlying datasource wouldn't have any effect, but it was worth checking just in case. The behavior you are seeing is very consistent with finalizable objects, particularly when there is no way to call `Dispose()` on them. Just one of the many reasons to avoid making objects finalizable unless there is a **very** good reason to do so.
Scott Dorman
Interestingly, having done further tests, it appears that if I populate the list before binding it, the rows are GC'ed correctly when the list is unbound and cleared. It is only if I bind the list first, and then add to it that the problem arises. Unfortunately, this is what I want to do, to update the grid in real time, pffft.
Andy