3

I am looking for a way to do this in C#:

  1. an Asker object will ask a Giver object for Resource objects.
  2. when asked, Giver will search it's Dictionary for existing matching Resource. If found, it will return the reference of the Resource; otherwise, it will create a the new Resource from database data, save that reference in Dictionary, and finally return the reference.
  3. the Asker may ask for the same Resource more than once, in which case Giver will return the same Resource from the Dictionary the same number of times.
  4. the Asker may at any time have no use for a given Resource, in which case, it does nothing further to the Resource.

  5. Problem: How can Giver detect for any Resource that it is no longer in use and remove it from the Dictionary? Preferably, Giver should do this without Asker's help.

Is this possible? I can't seem to solve this.

EDIT: Thanks everyone for the great replies. Especially the WeakReferences. I didn't know they were there. But I have 2 main objectives which I could have specified clearer.

  1. Giver should not rely on Asker to get notified.
  2. While a given Resource is in use, all of the references must be pointing to the same Resource so that modification to the Resource is reflected in all places where the same Resource is used.

EDIT: [Removed incorrect code block]

4
  • Sounds like garbage collection Commented Feb 1, 2011 at 15:49
  • Thanks for all the help. I have edited my post to include more specific contraints. Hope to get your feedback. Commented Feb 1, 2011 at 16:53
  • The class you've come up with won't actually solve the issue, since you hold on to a reference to the instance within your class. Take a look at the answer that I provided; it performs the necessary isolation using WeakReference in the cache and returns only a single instance of the resource to the asker. As with all solutions, it's not guaranteed to clean up anything (since your object may not, in fact, ever get garbage collected), but if it does, it will. Commented Feb 2, 2011 at 1:54
  • @Adam Thanks for your response. I have added my comments to your answer. Commented Feb 2, 2011 at 2:33

8 Answers 8

3

You could store a WeakReference to the resource in the dictionary instead of the resource itself. This wouldn't prevent the resource from being garbage collected.

When you fetched a value (the weak reference) from the dictionary, you'd then need to fetch the Target and see whether it's null. If it is, the resource has been garbage collected and you'll need to recreate it. Otherwise, you can return the target as the cached resource.

I don't believe there's much control over how "important" a WeakReference is deemed to be - I don't think you can say that it should make it as far as gen2, for example. Of course you could have some other data structure to make sure that any resource was cached for at least (say) 5 minutes by keeping a strong reference to it for that long.

If you do go for this approach, you may also want to periodically go through the dictionary and clear out entries for which the target has already been garbage collected, to avoid your dictionary getting full of useless entries. If the set of keys is fixed and not too huge, this may not be worth it though, particularly bearing in mind the synchronization you'd probably need.

Sign up to request clarification or add additional context in comments.

2 Comments

The doc for weak references states: "Avoid using weak references as an automatic solution to memory management problems. Instead, develop an effective caching policy for handling your application's objects." To be fair, I'm not sure what use WeakReference has at all, if it's not for handling memory management problems.
@MusiGenesis imo, basically, the caching policy could be "Always check issued references for null before using"
2

All this functionality is encapsulated in System.Web.Caching.Cache.

This can be safely used outside ASP.NET and has mechanism for expiration, reloading ...

Comments

1

To start, what you're talking about is the basic idea behind the IDisposable interface: a deterministic way for resources to be released. While its main usage is when interacting with unmanaged resources that require explicit release (or interacting with objects that do that), its usage is not restricted to that.

Unfortunately, it fails your last requirement: since it's deterministic, it has to be called by somebody. This somebody would have to be the Asker.

The only solution that I can come up with would be using the WeakReference class in your Giver object. This allows you to maintain a reference to an instance that doesn't prevent it from being garbage collected (after it's collected, your reference becomes null).

Unfortunately, this isn't deterministic. Your reference will become null (and IsAlive will be false) after the object is actually collected, which is not guaranteed to happen at any particular time (or at all during the lifetime of your application).

With those caveats in mind, you could something like this:

public class Giver
{ 
    private Dictionary<string, WeakReference> cache = 
        new Dictionary<string, WeakReference>();

    public object GetResource(string resourceName)
    {
        WeakReference output;
        object returnValue = null;

        if(cache.TryGetValue(resourceName, out output))   
        {
            if(output.IsAlive) returnValue = output.Target;

            if(returnValue == null) cache.Remove(resourceName);
        }

        if(returnValue == null)
        {
            returnValue = ...; // get the actual resource

            cache.Add(resourceName, new WeakReference(returnValue));
        }

        return returnValue;
    }
}

5 Comments

You method does not seem to work for me because for any Resource which Giver has given the Asker and while the Asker still has a [strong] reference to it, I would like Giver to return the same Resource reference. Since WeakReference.Target is indeterministically GC-ed, your method cannot fulfil this requirement. Can it?
@Jake: For any given resource name, the Giver will return the same resource reference. There's no duplication here. You want the Asker to maintain a strong reference to the resource; you want the Giver to keep the weak reference. The only difference between this and your requirement is that there can/will be an undefined amount of time from when the last strong reference (all in Asker) falls out of scope and when the object is actually collected. During this time, the Giver will still return the same instance. This is unavoidable without having the Asker signal that it's finished
@Jake: I'm not certain what you're asking. That block of code checks to see if the instance to which we have a weak reference has been collected (where IsAlive would be false). If it hasn't been (IsAlive == true), we grab an actual reference to the object using Target. If it has been (or if the reference was collected between the call to IsAlive and Target), we remove that weak reference from the cache.
@Jake: After that, if our output value is null (meaning that either we didn't have it to begin with or the copy in the cache has been GC'ed), we obtain the resource using whatever means you need (in this case, I believe, you said you wanted to get it from the DB), then add a WeakReference to it to the cache and return a normal reference to the instance we just retrieved.
thanks for the clarification. I misunderstood how WeakReferences work altogether in C#. (That block of code timedout before i could edit. it is deleted now.)
0

The Asker will have to tell Giver that it no longer uses a resource.

At this point Giver should remove the resource.

The Observer pattern can help here.

Comments

0

You probably need a Dictionary[string,WeakReference]. The MSDN has an example on how to use them to implement more or less the system you are asking for:

http://msdn.microsoft.com/en-us/library/system.weakreference.aspx

Just scroll down to the "Examples" section, where they show how to implement a cache of resources.

WeakReference do not lock objects down, they simply go to null when the object they are pointing to is reclaimed by the garbage collector.

Comments

0

You can use the WeakReference Class in the Giver.

Comments

0

One way to do this is with weak references. Here is an article I wrote about that approach a number of years ago:

http://www.devx.com/dotnet/Article/36286

2 Comments

Thanks, yours is quite interesting. Unfortunately, does not quite meet my requirements.. Would be useful in other scenarios though.
@JAke - Could you be more specific as to what requirements this approach doesn't meet? I re-read your question and this seems to hit on every one. Either way, it looks like you've found something that works and that's a good thing.
0

Further to Oded's comments, here's the link to the IObserver interface to get you started:

http://msdn.microsoft.com/en-us/library/dd783449.aspx

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.