.NET Forum / .NET Framework / New Users / July 2007
WeakReference not working?
|
|
Thread rating:  |
Pieter - 25 Jul 2007 14:53 GMT Hi,
We have written a cache, which can have different behaviours. One of these is a WeakReference-Cache. The purpose is that, once an object isn't referred anymore in the application, it should dissappear from the cache.
This works almost always fine, but not for some objects, and I can't find out why. For some reason, even when I do a "MyObject = Nothing" and a "GC.Collect", it still has its "WeakReference.IsAlive = True"...
Anybody knows why this happens? And what can I do about it? Should I implement IDisposable to all my objetcs? And how does that work? Do I have to do anything special in the overriden Dispose-method?
Thanks a lot in advance,
Pieter
This is how we did the GC.Collect and the removal of the not-anymore-used-objects...
Private Shared Sub GarbageCollect() Dim lstID As New List(Of Integer)
GC.Collect() 'premier collect GC.WaitForPendingFinalizers() 'attend la fin du thread GC.Collect() 'dexième collect pour tout enlever GC.WaitForPendingFinalizers() 'attend la fin du thread
For Each i As Integer In dicCacheWeakReference.Keys If Not dicCacheWeakReference(i).IsAlive Then lstID.Add(i) 'si l'objet n'existe plus, l'ajoute dans la liste à effacer End If Next
For Each intID As Integer In lstID dicCacheWeakReference.Remove(intID) 'efface les reférences morte du cache Next End Sub
Göran Andersson - 25 Jul 2007 15:37 GMT > Hi, > [quoted text clipped - 7 lines] > > Anybody knows why this happens? A garbage collection isn't guaranteed to collect _all_ objects that are collectable, it only collects the objects that are efficient to collect.
A garbage collection usually only collects objects in the first generation heap. As the objects that you cache probably lives for a longer time than most objects, they are likely to have been moved to the second or third generation heap.
> And what can I do about it? Should I > implement IDisposable to all my objetcs? And how does that work? Do I have > to do anything special in the overriden Dispose-method? Why is there any reason to do anything about it? If the garbage collector doesn't collect the objects, the memory that they are using isn't needed. If the application runs out of memory in the current heap, the garbage collector does a more thorough collection to collect anything that is possible, before more memory is requested from the system.
> Thanks a lot in advance, > [quoted text clipped - 23 lines] > Next > End Sub Why are you calling GC.Collect at all? The memory management handles itself, and there is hardly ever any reason to interfer with it.
Unless you know something important about the memory usage that the garbage collector don't, you will likely reduce the performance of the application rather than improve it.
 Signature Göran Andersson _____ http://www.guffa.com
Pieter - 25 Jul 2007 16:12 GMT > Why is there any reason to do anything about it? The whole purpose is not collecting memory, but throwing away the object...
This is what is needed: If the user wants to open object A, but object A is already opened (and used), it should return the same objet. But if it's not opened (or opened before but not used anymore), it should return a fresh copy of the database.
That's exactly why we are using WeakReferences...
> If the application runs out of memory in the current heap, the garbage > collector does a more thorough collection to collect anything that is > possible, before more memory is requested from the system. And can I force him to do this more thorough collection?
And better (because I don't really like using the garbage collector): isn't there another way to achieve this behaviour?
Thanks,
Pieter
Henning Krause [MVP - Exchange] - 25 Jul 2007 16:57 GMT >> Why is there any reason to do anything about it? > [quoted text clipped - 7 lines] > > That's exactly why we are using WeakReferences... And that's how it will work. But you can't force the GC to free your instance. It will do if it deems it necessary. Just don't worry about it.
>> If the application runs out of memory in the current heap, the garbage >> collector does a more thorough collection to collect anything that is >> possible, before more memory is requested from the system. > > And can I force him to do this more thorough collection? You can, but you shouldn't. Call GC.Collect(2); GC.WaitForPendingFinalizers(); GC.Collect(2);
But don't do it. In most cases, this will make things worse.
> And better (because I don't really like using the garbage collector): > isn't there another way to achieve this behaviour? No... that's (thankfully) .NET.
Kind regars, Henning Krause
John - 25 Jul 2007 21:14 GMT If done properly a weak reference will be collected during a full garbage collection (GC.Collect()). The fact that it is not collected shows that Pieter has a memory leak that needs to be corrected.
John
>>> Why is there any reason to do anything about it? >> [quoted text clipped - 31 lines] > Kind regars, > Henning Krause Henning Krause [MVP - Exchange] - 25 Jul 2007 22:28 GMT Hi John, You are right.
There is a pretty cool memory analzyer from SciTech. They also have a 30 days trial version.
Kind regards, Henning Krause
> If done properly a weak reference will be collected > during a full garbage collection (GC.Collect()). The [quoted text clipped - 38 lines] >> Kind regars, >> Henning Krause Göran Andersson - 26 Jul 2007 00:51 GMT >> Why is there any reason to do anything about it? > [quoted text clipped - 6 lines] > > That's exactly why we are using WeakReferences... A WeakReference doesn't work that way. The memory management in .NET doesn't use reference counting, so there is no way that a WeakReference can know when there are no more references to the object.
The way to control the life cycle of an object in .NET is to use the IDisposable interface.
What you need to do is use reference counting in your cache, and implement the IDisposable interface in the object. When the object is disposed, it should inform the cache so that it can decrement the reference count, so that the object can be removed from the cache when the reference count reaches zero.
>> If the application runs out of memory in the current heap, the garbage >> collector does a more thorough collection to collect anything that is >> possible, before more memory is requested from the system. > > And can I force him to do this more thorough collection? Yes, but you shouldn't.
> And better (because I don't really like using the garbage collector): isn't > there another way to achieve this behaviour? Exactly. You are trying to use the garbage collector for something that it can't do, so you should implement it in a way that works instead. :)
 Signature Göran Andersson _____ http://www.guffa.com
Henning Krause [MVP - Exchange] - 26 Jul 2007 08:14 GMT Hello,
> A WeakReference doesn't work that way. The memory management in .NET > doesn't use reference counting, so there is no way that a WeakReference > can know when there are no more references to the object. Yes it does work this way. A WeakReference does not have a strong reference to the object but holds the GCHandle of the item.
> The way to control the life cycle of an object in .NET is to use the > IDisposable interface. Nope. IDisposable is used to release unamanged resources. Not managed ones.
> What you need to do is use reference counting in your cache, and implement > the IDisposable interface in the object. When the object is disposed, it > should inform the cache so that it can decrement the reference count, so > that the object can be removed from the cache when the reference count > reaches zero. The whole GC is about not having to worry about reference counting. Why do you want to bring it back?
A WeakReference will work fine in a cache. The GC will release it if there is no other strong reference.
Kind regards, Henning Krause
Göran Andersson - 26 Jul 2007 11:59 GMT >> A WeakReference doesn't work that way. The memory management in .NET >> doesn't use reference counting, so there is no way that a >> WeakReference can know when there are no more references to the object. > > Yes it does work this way. A WeakReference does not have a strong > reference to the object but holds the GCHandle of the item. That's not what we are talking about. What Peter wants is to know if the object is used, not if it has been collected. A weak reference can not be used for that, because it doesn't work that way.
>> The way to control the life cycle of an object in .NET is to use the >> IDisposable interface. > > Nope. IDisposable is used to release unamanged resources. Not managed ones. As there are no destructors in .NET, the IDisposable interface is used when you need to control the life cycle of objects. It's ususally used because the object has unmanaged resourctes that needs to be released, but there is nothing that requires the object to have unmanaged resources.
>> What you need to do is use reference counting in your cache, and >> implement the IDisposable interface in the object. When the object is [quoted text clipped - 4 lines] > The whole GC is about not having to worry about reference counting. Why > do you want to bring it back? Because Peter needs to know if the object is used or not, and as there can be more than one reference to the object, the references needs to be counted.
> A WeakReference will work fine in a cache. The GC will release it if > there is no other strong reference. Yes, but that is not what Peter wants. Or in his own words:
"The whole purpose is not collecting memory, but throwing away the object"
 Signature Göran Andersson _____ http://www.guffa.com
John - 25 Jul 2007 21:10 GMT The fact that a weak reference is still alive after *multiple* full garbage collections is an indication that there is regular object reference pointing to the object. This is a memory leak and should be corrected.
I agree with you that in most cases GC.Collect should not be used except for debugging. However, if an object (that should be collectable) survives multiple full collections then it is in fact not collectable and is evidence of a memory leak.
John
>> Hi, >> [quoted text clipped - 60 lines] > garbage collector don't, you will likely reduce the performance of the > application rather than improve it. Pieter - 26 Jul 2007 08:58 GMT Thanks all for the help. I thought too about a memory leak, but it's jsut that weard because: - We have like 7 'main' objects that are threated exactly the same, but only 2 of them have this problem. - All are of the same kind, with some parent-child lists in it, but nothing special - The cache and weak reference behaviour is tested with NUnit: An objectsi created, set to Nothing, GC.collected, and that's it. No other references pointing to it...
I'll take a look at the profilers and let something know if I find something
:-) Thanks a lot,
Pieter
For instance the tests that fails: <Test()> Public Sub CacheTest()
'creation of a new clsCotation, based on 2 other objects Dim clsF As New clsCotation(MyRequisition, MyFournisseur)
clsF.Titre = "Cache Test" clsF.PrixTotalNet = 20 'doit avoir prix pour PF 'save the object clsF facCotation.SaveOne(clsF) 'save the ID intCotationID = clsF.CotationID
'set clsF = nothing (and all it's child-list and child-objects etc.) clsF.MyArticles = Nothing clsF.MyConditionnements = Nothing clsF.Requisition = Nothing clsF.Fournisseur = Nothing clsF.Client = Nothing clsF = Nothing
'another clsCotation Dim clsF3 As clsCotation 'select the cotation from the cache, but it should be GC-ed... (but isn't!!!) clsF3 = facCotation.SelectOneByID(intCotationID, CacheUsage.cuCacheOnly) Assert.AreEqual(Nothing, clsF3, "because the object should have been GC-ed, it should return Nothing, but this tests fails!") clsF3 = Nothing
> The fact that a weak reference is still alive after *multiple* > full garbage collections is an indication that there is regular [quoted text clipped - 73 lines] >> garbage collector don't, you will likely reduce the performance of the >> application rather than improve it. John - 25 Jul 2007 20:49 GMT Hi Pieter,
The normal purpose for creating weakly referenced objects is to allow them to remain in memory as long as memory permits. If there is memory pressure the garbage collector will run and wr objects may be collected. This way if memory is abundant your wr cache objects will be in memory, if not, they will be collected (forcing you to re-load them the next time they are needed).
You can simulate this situation by running GC.Collect() and then WaitForPendingFinalizers(). If you are using wr correctly they will be be removed from memory after GC.Collect.
Please note that I am *not* saying that you run the garbage collector manually when using wr. The above is for testing/debugging purposes only to help simulate the situation where wr objects are removed from memory.
One mistake people make is creating a regular (non-weak) object reference to an object that is the target of a wr. In this case the object will *survive* garbage collections which is not the behavior you wanted when you decided on using weak references.
You can use CLR Profiler (free) or .NET Memory Profiler ($) to help you track down the reference that is causing the wr to not be collected.
John
> Hi, > [quoted text clipped - 37 lines] > Next > End Sub Pieter - 26 Jul 2007 09:50 GMT > You can use CLR Profiler (free) or .NET Memory Profiler ($) > to help you track down the reference that is causing the wr > to not be collected. Ouwch, I got very nice and colourfull schema's with the CLR Profiler, but in which screen exactly can I track down my problem? hihi :-)
Pieter - 27 Jul 2007 14:50 GMT I'm not finding a way via those Profilers to see what's putting a reference to my object :-S Anybody has another idea? Or can someone point me out how I should be able to see it?
Thanks a lot,
Pieter
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|