Weak references in .NET (Part I)

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

In this article, we are going to learn what are weak reference types and explore the scenarios for its usage.

Introduction


Some terms come as a surprise for programmers even with few years of experience in programming. The reasons for this could be as the most of the experience is from the area of writing data centric applications and which may not require the real power and use of capabilities of the frameworks. Also most of the work is not from scratch but from something which is ready or in production making the developers to continue from that point of time robbing them opportunity for redesign and re-jig.

.NET framework (or for the sake many frameworks) have many such constructs / concepts which I am sure majority of the developers must be unaware and but still has great potential for exploring and usage in scenarios where performance, scalability etc becomes need of the hour.

One of such concept is weak reference which is there for long time since framework 1.1 days.

Description


Before getting into what is a weak reference, let’s get clarity about what is the other type i.e. strong reference. 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.

This is considerably a vast topic but this write –up should be able to serve as a starter for exploring the world of weak references.

Scenario

We have a class named Person and also we need a byte array representing the image of the person. Now there would be thousands of records for person which is having associated image bytes. Generally this can be showed in data-grids (grid-views) where in thumbnail of image can be displayed. Such thumbnail would be prepared from byte array representing the image. 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.

Example:

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

public class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

public int PersonId { get; set; }

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

{

get { return FirstName + " " + LastName; }

}

}

 

/// <summary>

/// This class creates byte arrays to simulate image data asscoiated with person -- image read into ///bytearray

/// </summary>

public class ImageData

{

private byte[] byteData;

private string bytedataName;

public ImageData(int size)

{

byteData = new byte[size * 1024];

bytedataName = size.ToString();

}

public string Name// Simple property.

{

get { return bytedataName; }

}

}

 

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

/// <summary>

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

/// </summary>

public class PersonsCache

{

static Dictionary<int, WeakReference> _personsImageDataCache;// cache for imagedatas

static Dictionary<int, Person> _personsCache;//cache for person objects

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

private string personName = string.Empty;

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

{

get { return _personsImageDataCache.Count; }

}

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

{

get { return regenarationCount; }

}

public string PersonName

{

get { return personName; }

}

// Accesses a image data object from the cache and If the object was reclaimed for garbage collection then

//create a new data object at that index location.

public ImageData this[int index]

{

get

{

personName = _personsCache[index].PersonName;

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

ImageData imageData = _personsImageDataCache[index].Target as ImageData;

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

{

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

imageData = new ImageData(index);

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 PersonsCache(int count)

{

_personsImageDataCache = new Dictionary<int, WeakReference>();

_personsCache = new Dictionary<int, Person>();

// 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);

_personsImageDataCache.Add(person.PersonId, new WeakReference(new ImageData(person.PersonId), false));

}

}

}

Console application

class Program

{

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

{

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

Random random = new Random();

PersonsCache personsCache = new PersonsCache(cacheSize);// Create the cache with defined size

string dataName, personName;

// 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

GC.Collect();

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

{

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

dataName = personsCache[index].Name; // Access the object by getting a property value

Console.WriteLine("ImageData Name: " + dataName);

personName = personsCache.PersonName;

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

}

// Show results.

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

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

Console.ReadLine();

}

}

Output:

Two kinds of output are displayed.

I: GC not collecting the weak references

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

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

Regenerate object at 1: No

ImageData Name: 1

Person Name: 1 1

Regenerate object at 2: No

ImageData Name: 2

Person Name: 2 2

Regenerate object at 1: No

ImageData Name: 1

Person Name: 1 1

Regenerate object at 3: No

ImageData Name: 3

Person Name: 3 3

Regenerate object at 0: No

ImageData Name: 0

Person Name: 0 0

Cache size: 5, Regenerated: 0%

***************************************************************
II: GC collecting the weak refrences

GC.Collect() is uncommented.

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

Regenerate object at 3: Yes

ImageData Name: 3

Person Name: 3 3

Regenerate object at 1: Yes

ImageData Name: 1

Person Name: 1 1

Regenerate object at 3: Yes

ImageData Name: 3

Person Name: 3 3

Regenerate object at 1: Yes

ImageData Name: 1

Person Name: 1 1

Regenerate object at 2: Yes

ImageData Name: 2

Person Name: 2 2

Cache size: 5, Regenerated: 100%

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

Conclusion:

The output clearly demonstrates what happens when one uses the 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). One needs to use property “Target” for using weak reference.

The common usage for these types can be

  1.  Implementing caching functionality
  2.  Where large objects like byte array, streams, documents would be residing in the memory and those may not be needed all the time for the application but can pose an issue from performance perspective
  3.  Display of thousands of records which may be required to be displayed once or rarely but application would be switching to such display once in a while.

Hopefully, this write up helps to understand the fundamental of weak reference and give direction for using them.

Read the 2nd Part of this article here.

References:

http://en.wikipedia.org/wiki/Weak_reference

http://msdn.microsoft.com/en-us/library/system.weakreference(v=VS.100).aspx
 

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: Tripati_tutu on: 6/29/2011 | Points: 25
Good one...
Thanks for sharing !!!
Posted by: Anu4smile on: 6/30/2011 | Points: 25
Thanks Visvaas for sharing this knowledge on references.
You have given very clear picture of weak references. Worth reading one !

Login to post response

Comment using Facebook(Author doesn't get notification)