Weak references in .NET (Part II)

Vishvvas
Posted by in .NET Framework category on for Advance level | Points: 250 | Views : 6733 red flag
Rating: 4.5 out of 5  
 2 vote(s)

This is continutaion of earlier article on the same subject, delving into long weak references.

Introduction & backgound


We have seen fundamentals of weak reference in previous article http://www.dotnetfunda.com/articles/article1419-weak-references-in-net-.aspx and we saw a practical example of usage of weak reference. A little excerpt from the said article “A strong reference is a reference pointing to an object created by new operator and the object would reside in the memory as long as the reference is pointing to an object in turn it protects the referenced object from being collected by GC (garbage collector). A weak reference is a reference that doesn’t protect the referenced object from being collected which means the object referenced by weak reference is considered unreachable (or weakly reachable) and so may be collected at any time, more precisely when  more memory is in needed. Different languages like java, C#, VB.NET, Python, Perl, Lisp etc support this feature.”

Weak reference are useful for objects which would use a lot of memory and these objects can be recreated easily if they are collected by GC.

To establish a weak reference with an object, you create a WeakReference using the instance of the object to be tracked. One can specify ‘false’ in the constructor if short weak reference is to be used otherwise ‘true’ for long weak reference. One then set the Target property to that object and set the object to null.

Let’s delve more into world of weak references and learn about long and short weak reference.

Description


The target of short weak reference becomes null when it is reclaimed by GC. A long weak reference is retained after the object’s finalize method is called i.e. when generally IDisposable pattern is implemented for unmanaged objects like database connections or file handles. When object doesn’t have Finalize method then the short weak reference functionality is applied. Such weak reference is valid until target is collected which can happen anytime after finalizer is run. This we can see that no object is reclaimed by GC even calling GC.Collect(); in case of long weak reference as Targets finalize method haven’t been called.

Scenario: We have a class named Person and also we need images representing the image of the person. We know Image type implements IDisposable (http://msdn.microsoft.com/en-us/library/system.idisposable.aspx) and hence can be used for long weak reference. Now there would be thousands of records for person which is having associated images. Generally this can be showed in data-grids (grid-views) or tree views where in thumbnail of image can be displayed. Such thumbnail would be prepared from image (Image. GetThumbnailImage() method). As this display may not critical to application i.e. this may not be required at many places and not much of business logic depends on this image display, one could think of using weak reference and here we would be using long. In previous article we employed short weak references.


Example:

Examples are in C# and exercise is done as console application.

public class Person

    {

        public string FirstName { getset; }

        public string LastName { getset; }

        public int PersonId { getset; }

 

        public Person(string firstName, string lastName)

        {

            this.FirstName = firstName;

            this.LastName = lastName;

        }

        public  Person(string firstName,string lastName, int ID)

        {

            this.FirstName = firstName;

            this.LastName = lastName;

            this.PersonId = ID;

        }

        public  string  PersonName

        {

            getreturn FirstName + " " + LastName;}

        }

    }

 

A class meant for holding different objects of persons and images, we would treat it as cache.

/// <summary>

    /// The class to hold different objects of Person and behave as cache

    /// </summary>

public class ImageCache

 {

    int regenarationCount = 0;// Track the number of times an object is regenerated after collection by GC

        private string personName = string.Empty;

 

        static Dictionary<intWeakReference> _personsImageCache;// cache for imagedatas

        static Dictionary<intPerson> _personsCache;//cache for person objects

        public int Count  // Returns the number of items in the cache.

        {

            get { return _personsImageCache.Count; }

        }

        public int RegenerationCount // Returns the number of times an  object had to be regenerated.

        {

            get { return regenarationCount; }

        }

        public string PersonName

        {

            get { return personName; }

        }

        public Image this[int index]

        {

            get

            {

                personName = _personsCache[index].PersonName;

                // Obtain an instance of a data  object from the personcache of  of weak reference objects.

                Image imageData = _personsImageCache[index].Target as Image;

                if (imageData == null//If the object was reclaimed, so generate a new one.

                {

                    Console.WriteLine("Regenerate object at {0}: Yes", index);

                    imageData =  Image.FromFile("@C:\\Users\\Public\\Pictures\\Sample Pictures\\Desert.jpg");

                    regenarationCount++;

                }

                else // As Object is not reclaimed so can be obtained with the weak reference.

                {

                    Console.WriteLine("Regenerate object at {0}: No", index.ToString());

                }

                return imageData;

            }

             

        }

          public ImageCache(int count)

        {

            _personsImageCache = new Dictionary<intWeakReference>();

            _personsCache = new Dictionary<intPerson>();

            // Add data objects with a short weak reference to the cache.

            for (int i = 0; i < count; i++)

            {

                Person person = new Person(i.ToString(), i.ToString(), i);

                _personsCache.Add(person.PersonId, person);

                //Long weak reference

                _personsImageCache.Add(person.PersonId, newWeakReference(Image.FromFile("C:\\Users\\Public\\Pictures\\Sample Pictures\\Desert.jpg"), true));

            }

        }

    }

 

Console application


  static void Main(string[] args)// for long Weakreference demo

        {

            int cacheSize = 5;//define the cache size.  For demonstration purpose, its taken very small.

            Random random = new Random();

            ImageCache imageCache = new ImageCache(cacheSize);// Create the cache with defined size

            string  personName;

            System.Drawing.Image image;

            // GC.Collect() is to be commented for ouput I where in the objects from cache are not collected by GC

            //and uncommented for output II

            Console.WriteLine("Demonstration of Long weak reference");

            Console.WriteLine("In method Main (...), the call to GC.Collect() is commented.");

             //GC.Collect();

            Console.WriteLine("***************Random Display of objects.***************");

            for (int i = 0; i < imageCache.Count; i++)

            {

                int index = random.Next(imageCache.Count);// Randomly access objects in the cache

                image = imageCache[index]; // Access the object by getting a property value

             //   Console.WriteLine("ImageData Name: " + image.Height.ToString());

                personName = imageCache.PersonName;

                Console.WriteLine("Person Name: " + personName);

            }

 

            double regenPercent = (((imageCache.RegenerationCount) * (100)) / (imageCache.Count));

            Console.WriteLine("Cache size: {0}, Regenerated: {1}%", imageCache.Count.ToString(), regenPercent.ToString());

            Console.WriteLine("***************************************************************");

            Console.ReadLine();

        }


Output: Two kinds of output are displayed.

I: GC not collecting the weak references as GC.Collect() is commented

Demonstration of Long weak reference

In method Main (...), the call to GC.Collect() is commented.

***************Random Display of objects.***************

Regenerate object at 4: No

Person Name: 4 4

Regenerate object at 4: No

Person Name: 4 4

Regenerate object at 1: No

Person Name: 1 1

Regenerate object at 3: No

Person Name: 3 3

Regenerate object at 3: No

Person Name: 3 3

Cache size: 5, Regenerated: 0%

***************************************************************

II: GC not collecting the weak references as they are long weak reference and application has gained the strong references

Demonstration of Long weak reference

In method Main (...), the call to GC.Collect() is uncommented.

***************Random Display of objects.***************

Regenerate object at 4: No

Person Name: 4 4

Regenerate object at 4: No

Person Name: 4 4

Regenerate object at 1: No

Person Name: 1 1

Regenerate object at 2: No

Person Name: 2 2

Regenerate object at 4: No

Person Name: 4 4

Cache size: 5, Regenerated: 0%

***************************************************************

Summary & Conclusion


The output clearly demonstrates what happens when one uses the long weak references. The weakly referenced objects are collected by GC (here is specifically called upon for demo but in practical scenarios when needed GC would collect these objects) when they are short weak reference and in case of long weak reference, it is retained even after the object’s Finalize method is called. So there are no regenerations occurred as the application has regained a strong reference to it. One needs to use property “Target” for using weak reference.

  • Use long weak references only when necessary as the state of the object is unpredictable after finalization.
  • Avoid using weak references to small objects because the pointer itself may be as large or larger.
  • Weak references shouldn’t be seen as an automatic solution to memory management problems. Instead, effective caching policy for handling your application's objects could help in better memory management

References:

Page copy protected against web site content infringement by Copyscape

About the Author

Vishvvas
Full Name: Vishwas Sutar
Member Level: HonoraryPlatinum
Member Status: Member,MVP
Member Since: 5/30/2011 2:13:10 AM
Country: India

http://www.dotnetfunda.com
Extensive and rich experience across gamut of technologies and programming languages like PB,VB,C++,VB.NET, C#, Classic ASP,ASP.NET, ASP.NET MVC.

Login to vote for this post.

Comments or Responses

Posted by: Naimishforu on: 7/15/2011 | Points: 25
I was looking for the first part of it. it's very nice...reading part 2 :)

Login to post response

Comment using Facebook(Author doesn't get notification)