4
\$\begingroup\$

I'm developing an application to manage a player card-library from an online game. Each card has an image that is stored on disk with a numeric code, for example, the card with ID=1234 has his image stored as 1234.png and all the images are stored on the same folder.

As of now there are more than 3500 images for a total of 1 GB of hard disk usage.

The app doesn't need all the images loaded on memory, but depending on the context it may need from 8 to 100 images loaded on screen, and the next moment it may need a 100 different images.

As of now the images are loaded using IValueConverter and DataTemplate without storing on code behind the image, so everytime an image is needed, it is loaded from disk.

That is the current state of the project.


Now this is the code that I want to implement:

public class ImageAccessor
{
    private string Filepath;
    private Dictionary<int, WeakReference> References;

    public ImageAccessor(string filepath)
    {
        Filepath = filepath;
    }

    public BitmapImage GetImage(int id)
    {
        BitmapImage image = null;
        WeakReference reference = null;

        if (!References.TryGetValue(id, out reference))
        {
            image = GetFromDisk(id);
            reference = new WeakReference(image);
            References[id] = reference;
        }
        else
        {
            image = reference.Target as BitmapImage;
            if (image == null)
            {
                image = GetFromDisk(id);
                reference.Target = image;
            }
        }

        return image;
    }

    private BitmapImage GetFromDisk(int id)
    {
        Uri uri = new Uri(Filepath + id + ".png");
        return new BitmapImage(uri);
    }
}

I don't want to implement a singleton of that class but for now let's assume that my project always uses the same instance.

Everywhere that I read about WeakReference they recommend using it for "a single large object", but what if I want to use it on "a lot of relative small-medium size objects (200~500kb each)". Except from the advice of using them for big objects, those images meet the rest of the requirements:

  • Having all of them all the time on memory would be very costly (1GB on RAM)
  • Some images may not be used for the entire life of the app
  • Some images may be used only one or a couple of times
  • Some images may be used lots of times

And by using an image I mean displaying it on a Image control

I've never worked with weak references, and I still need to do some benchmarks to see if they are worth it, but I want to know if this code:

  • Is safe?
  • May incur on memory problems?
  • It can be improved?

For the sake of simplicity assume this:

  • The filepaths will always be correct
  • Every ID will correspond to an existing image always
  • Images will not be modified
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! What you can and cannot do after receiving answers. I have rolled back your edit. \$\endgroup\$ – Heslacher Jan 15 '15 at 10:17
  • \$\begingroup\$ @Heslacher you are right =) I'll follow the path of mark as correct answer because it truly gave me good advice on what I should do and I'll create a new answer. Is there any way I can see the rolled back version so I use it as a sketch for the new question? \$\endgroup\$ – Guillermo Mestre Jan 15 '15 at 11:04
  • \$\begingroup\$ If you click on the "edited xx mins ago" above my icon you will see the edit history. \$\endgroup\$ – Heslacher Jan 15 '15 at 11:05
  • \$\begingroup\$ Here is the follow up on the question: codereview.stackexchange.com/questions/77588/… \$\endgroup\$ – Guillermo Mestre Jan 15 '15 at 11:18
6
\$\begingroup\$

It looks like weak reference would serve the purpose of what you are trying to achieve [IF] those images will go out of scope (not being directly referenced in any execution path) after handing them back to the caller of that method then they will be collected by GC at some point.

This MSDN article explains weak references in .net, I'll quote it here:

The garbage collector cannot collect an object in use by an application while the application's code can reach that object. The application is said to have a strong reference to the object.

A weak reference permits the garbage collector to collect the object while still allowing the application to access the object.

A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist. When you use a weak reference, the application can still obtain a strong reference to the object, which prevents it from being collected. However, there is always the risk that the garbage collector will get to the object first before a strong reference is reestablished. Weak references are useful for objects that use a lot of memory, but can be recreated easily if they are reclaimed by garbage collection.

While your code should work fine, I would consider using an in-memory Cache instead with (either or both) capping the TTL (time to live) or count of objects that can occupy that cache (adding new items to the cache would invalidate and remove older items to maintain the capacity).

Check out MemoryCache class in .net framework.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.