Posted by: Cirilo Meggiolaro | 03/1/2009

Tip of the day #138 – WeakReference

The garbage collector (GC) usually collects objects when they are not accessible by the application’s code anymore. This concept is known as strong reference.

What about a weak reference? The idea of a weak reference is to keep an object “collectable” by the GC while it’s still accessible by the application’s code. Ok, most of you have asked yourselves: what if the runtime tries to access an object that has been released? The idea is to rebuild the object on the fly when it’s been released.

This approach may worth for objects that consume a large amount of memory and that are easy to be rebuilt.

The WeakReference class

The WeakReference class provides a set of methods to apply the weak reference concept to your code.

Constructors

  • public WeakReference(object target);
  • public WeakReference(object target, bool trackResurrection);
  • protected WeakReference(SerializationInfo info, StreamingContext context).

Properties

  • public virtual bool IsAlive: Read-only property that retrieves a flag that indicates whether the object referenced by the WeakReference has been collected by the garbage collector (GC);
  • public virtual object Target: Gets or sets the object referenced by the WeakReference object;
  • public virtual bool TrackResurrection: Read-only property that retrieves a flag that indicates whether the object referenced by the WeakReference is tracked after it is finalized.

Method

  • public virtual void GetObjectData(SerializationInfo info, StreamingContext context): Populates a SerializationInfo object with all the data needed to serialize the current WeakReference object.

Short and Long weak references

There are two types of weak references:

  • Short: The default weak reference where the object referenced by the WeakReference class becomes null after being collected by the GC;
  • Long: Passing a Boolean value as the second parameter of the WeakReference constructor will make the weak reference to be retained after the object’s Finalize method call.

Some rules

  • The weak reference should not be used as your memory management engine;
  • Avoid use weak references for small objects.

How to…

The example I am posting on this tip has the purpose of demonstrate how the WeakReference class works and for brevity extra pieces of code have been removed. All the code posted is enough to run the example though.

Let’s start creating our base object. In this case, a Customer type class that contains some properties being one of them a List of Order type objects. On the Customer constructor I am adding several Order objects to the current customer just to increase the object size and make the example able to be reproduced on most part of the computers.

public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime DOB { get; set; }
    public bool Active { get; set; }
    public OrderCollection Orders { get; set; }

    public Customer()
    {
        Orders = new OrderCollection();

        /// Adds new order instances just
        /// to make the object larger.

        for (int i = 0; i < 1000; i++)
        {
            Orders.Add(new Order() { ID = i, BilledTotal = (i + 1) * 1000 });
        }
    }
}

public class Order
{
    public int ID { get; set; }
    public decimal BilledTotal { get; set; }
}

The OrderCollection class stores a dictionary of weak references orders and has an indexer that is used to check if the object is valid to be retrieved or reconstruct it. For this example I am just recreating the instance and I am not concerned about the data itself. The indexer also writes a message to the console window to inform whether the order was retrieved from the collection or recreated. The additional methods and properties are pretty straightforward and self-explanatory.

public class OrderCollection
{
    /// <summary>
    /// Stores a dictionary of order weak references.
    /// </summary>

    static Dictionary<int, WeakReference> _orders;

    /// <summary>
    /// Class constructor.
    /// </summary>

    public OrderCollection()
    {
        /// Instantiates the orders dictionary.
        if (_orders == null)
            _orders = new Dictionary<int, WeakReference>();
    }

    public void Add(int index, Order order)
    {
        _orders.Add(index, new WeakReference(order, false));
    }

    /// <summary>
    /// Gets the number of orders
    /// in the collection.
    /// </summary>

    public int Count
    {
        get
        {
            return _orders.Count;
        }
    }

    /// <summary>
    /// Item indexer.
    /// </summary>
    /// <param name=”index”>Index to retrieve.</param>
    /// <returns>The order object.</returns>

    public Order this[int index]
    {
        get
        {
            /// Retrieves the item in the
            /// collection object by its index.

            Order order = _orders[index].Target as Order;

            /// Checks if the object is a valid instance.
            if (order == null)
            {
                /// If the instance has been released recreate it.
                order = new Order() { ID = index };

                Console.WriteLine(“Order object has been reconstructed at index {0}”, index);
            }
            else
            {
                Console.WriteLine(“Retrieving Order object at index {0}”, index);
            }

            /// Returns the valid Order instance.
            return order;
        }
    }
}

Executing the code

Customer cust = new Customer();
decimal billedTotal = 0;

for (int i = 0; i < cust.Orders.Count; i++)
{
    billedTotal = cust.Orders[i].BilledTotal;
}

Output

The following output shows that after the order number 653, all objects were reconstructed.

Retrieving Order object at index 0

Retrieving Order object at index 646
Retrieving Order object at index 647
Retrieving Order object at index 648
Retrieving Order object at index 649
Retrieving Order object at index 650
Retrieving Order object at index 651
Retrieving Order object at index 652
Retrieving Order object at index 653
Order object has been reconstructed at index 654
Order object has been reconstructed at index 655
Order object has been reconstructed at index 656
Order object has been reconstructed at index 657
Order object has been reconstructed at index 658
Order object has been reconstructed at index 659
Order object has been reconstructed at index 660

Order object has been reconstructed at index 1000


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: