Question about WeakReferences
I have a question about WeakReferences.
I am currently in the process of writing a "Resource Manager" that needs to maintain references to the generated texture objects. I have a dictionary like:
Dictionary<uint, WeakReference>
If the first, as you might have guessed, is the resource ID and the second parameter is the WeakReference for the resource itself.
Currently, my resources have a way to free themselves from their owner (i.e. the resource manager). They do this when calling a method in the Resource Manger, passing this reference to it. ResMgr does a lookup if it is the resource it stores the bookmark on, and if so, something like this:
WeakReference result;
if (m_Resources.TryGetValue(ResourceId, out result))
{
if (result.IsAlive)
return;
(result.Target as Resource).free(); // free for good
m_Resources.Remove(ResourceId);
}
The problem I am facing is that the part after:
if (result.IsAlive)
is never reached because there are still links to the resource.
The thing is, I only have one link of the resource in question and it is released as:
resource.free(); // calls internally its owner (i.e. ResMgr)
resource = null;
I think the left link will be the "resource" variable, but I cannot set it to null because I need to call for free first. Quite a dilemma ...
The good thing I wanted to achieve with this is a resource manager that keeps references to its own resources and releases them ONLY if there is no reference so that nothing will mess up.
Any idea how I can solve this in a clean way?
PS: Is there a way to get the reference score somehow?
Thanks in advance!
Mfg Imp
a source to share
I recommend you look at caching or link count. Weak links were never intended to be used as a caching system.
.NET does not have a "reference count"; objects are either referenced or not. If you want an actual reference count, I would recommend building on RefCountDisposable
from the Rx library , which is reference counted IDisposable
.
a source to share
I would have done otherwise. I could, internally, store the WeakReference for the object, but I would give it a hard reference back. Consumers should not remove an item from the resource manager unless they know they have a single reference to it and they don't need to. Otherwise, they should simply let the system determine when to delete the referenced object. Thus, since a (hard) reference to the object exists, it will remain in memory. You can remove it from the dictionary, but you only remove this entry, that is, any new requests for this would have to create a new object, even if other users had a link to the old object. The search process should recreate the object if the weak link is inactive.
public ResourceManager<T>
{
private Dictionary<uint,WeakReference> Cache = new Dictionary<uint,WeakReference>();
public T this[uint key]
{
var obj = (T)this.Cache[key].Target;
if (obj == null)
{
obj = ...recreate resource...
this.Cache[key] = obj;
}
return obj;
}
public void Remove( uint key )
{
this.Cache.Remove(key);
}
}
a source to share
If result.IsAlive is false, then result.Target will be null.
You might want to look at finalizers and / or ConditionalWeakTable , they can help you with a solution.
a source to share