简体   繁体   中英

C# “shared pointer” for alternative memory management?

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]

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

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

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.

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;
    }
}

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.

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.

您可以在Giver使用WeakReference类

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM