Reputation: 618
For a cache class I need to get notified if an object is garbage collected (to remove the according entries from my cache). What is the best way to do so? Sending an event from the destructor?
I am writing a cacher/memoizer for functions that take one huge parameter-tree object and many small value type parameters, e.g.,
double myFunc(HugeParTree parTree, int dynPar1, double dynPar2)
I want to cache these functions in the following way:
parTree
changes, which seldomly happens, all according cache entries are deleted (via Observer pattern). (parTree.Equals()
is just too expensive; it compares 100+ value types).Code looks like this right now (for one value parameter):
public class CachedFunction1ObsPar1Par<TRet, TObsPar1, TPar1>
where TObsPar1 : IObservable, IProvideGUID
{
public delegate TRet ValueCalculator(TObsPar1 obsPar1, TPar1 par1);
public CachedFunction1ObsPar1Par(ValueCalculator calc)
{
_calc = calc;
}
#region members
private ValueCalculator _calc;
private Dictionary<Guid, Dictionary<TPar1, TRet>> _cache =
new Dictionary<Guid, Dictionary<TPar1,TRet>>();
#endregion
public TRet value(TObsPar1 obsPar1, TPar1 par1)
{
TRet result;
bool cacheHit = checkCache(obsPar1, par1, out result);
if (cacheHit)
{
Debug.Assert(result.Equals(_calc(obsPar1, par1)));
return result;
}
else
{
result = _calc(obsPar1, par1);
_cache[obsPar1.GUID].Add(par1, result);
return result;
}
}
private bool checkCache(TObsPar1 obsPar1, TPar1 par1, out TRet result)
{
if (!_cache.ContainsKey(obsPar1.GUID))
{
_cache.Add(obsPar1.GUID, new Dictionary<TPar1, TRet>());
obsPar1._changed += this.invalidateCache;
}
Dictionary<TPar1, TRet> guidCache = _cache[obsPar1.GUID];
bool success = guidCache.TryGetValue(par1, out result);
return success;
}
private void invalidateCache(object sender)
{
TObsPar1 obsPar = (TObsPar1)sender;
_cache.Remove(obsPar.GUID);
obsPar._changed -= this.invalidateCache;
}
}
I haven't tested this yet, as I still have the problem that cache entries never get removed after the according parTree is not used any more. I'd love a synchronous solution without repeated "scans" for very old cache entries.
Upvotes: 2
Views: 1771
Reputation: 17509
Henk already mentioned the flaw in your requirement.
But, just to answer your question. To know when an object is being garbage collected you can write a destructor for that object.
~YourClass();
As per MSDN:
This method is automatically called after an object becomes inaccessible
Though it's never recommended to rely on GC or destructor.
Upvotes: 2
Reputation: 50692
You could define an interface 'ICacheable' that must be implemented by the objects in the cache. In a method of the interface RemoveFromCache()
you could search the cache for its child objects and remove them.
When you remove an item from the cache, test it for the interface and call RemoveFromCache()
.
This is similar to IDisposable.
Garbage collection is not something to count on because you never know when it will run.
Upvotes: 1
Reputation: 273784
For a cache class I need to get notified if an object is garbage collected (to remove the according entries from my cache). What is the best way to do so? Sending an event from the destructor?
If your cache holds normal (strong) references the items will never be collected.
If your cache holds WeakReferences you do not have to remove anything.
Upvotes: 8