ENTERPRISE

Memory Management : Force a Garbage Collection, Create a Cache That Still Allows Garbage Collection

10/4/2012 3:48:22 AM

Force a Garbage Collection

Scenario/Problem:You think you need to force a garbage collection.
Solution:The short answer is, don’t. You are unlikely to outguess the garbage-collection system for efficiency. That said, if you really know what you’re doing and you’re going to measure the effects, here’s how to do it:
GC.Collect();

One reason why people force a collection is that they’re beginning a performance-sensitive operation that they don’t want interrupted by garbage collection. However, the garbage collection system in .NET 4 has undergone major revision from previous versions and now does more collections in the background, so the need to do forced collections should be lessened.

Create a Cache That Still Allows Garbage Collection

Scenario/Problem:You want to cache objects (say, from a database) but still allow them to be garbage collected when necessary.
Solution:The problem is that just holding a reference to an object prevents it from being garbage collected. Enter WeakReference.

This simple Cache class uses WeakReference objects to store the actual values, allowing them to be garbage collected as needed.

public class Cache<TKey, TValue> where TValue:class
{
    //store WeakReference instead of TValue,
    //so they can be garbage collected
    private Dictionary<TKey, WeakReference> _cache =
             new Dictionary<TKey, WeakReference>();

    public void Add(TKey key, TValue value)
    {
        _cache[key] = new WeakReference(value);
    }

    public void Clear()
    {
        _cache.Clear();
    }

    //since dead WeakReference objects could accumulate,
    //you may want to clear them out occasionally
    public void ClearDeadReferences()
    {
        foreach (KeyValuePair<TKey, WeakReference> item in _cache)
        {
            if (!item.Value.IsAlive)
            {
                _cache.Remove(item.Key);
            }
        }
    }

    public TValue GetObject(TKey key)
    {
        WeakReference reference = null;
        if (_cache.TryGetValue(key, out reference))
        {
            /* Don't check IsAlive first because the
             * GC could kick in right after anyway.
             * Just retrieve the value and cast it. It will be null
             * if the object was already collected.
             * If you successfully get the Target value,
             * then you'll create a strong reference, and prevent
             * it from being garbage collected.
             */
            return reference.Target as TValue;
        }
        return null;
    }
}

					  

Note

Weak references should never be used for small items, and you should not rely on them as a crutch to solve memory problems for you. They are best used for items that can use a lot of memory, but are easily recreated as needed, such as in cache situations where it would be nice if the object were still around in memory, but you still want it to be garbage collected eventually.


This test program shows how it could be used:

class Program
{
    class Book
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
    };

    static void Main(string[] args)
    {
        Cache<int, Book> bookCache = new Cache<int, Book>();
        Random rand = new Random();
        int numBooks = 100;

        //add books to cache
        for (int i=0;i<numBooks;++i)
        {
            bookCache.Add(i, GetBookFromDB(i));
        }

        //lookup random books and track cache misses
        Console.WriteLine("Looking up books...hit any key to stop");
        long lookups = 0, misses = 0;
        while (!Console.KeyAvailable)
        {
            ++lookups;
            int id = rand.Next(0, numBooks);
            Book book = bookCache.GetObject(id);
            if (book == null)
            {
                ++misses;
                book = GetBookFromDB(id);
            }
            else
            {
                //add a little memory pressure to increase
                //the chances of a GC
                GC.AddMemoryPressure(100);
            }
            bookCache.Add(id, book);
        }
        Console.ReadKey();
        Console.WriteLine("{0:N0} lookups, {1:N0} misses",
                          lookups, misses);
        Console.ReadLine();
    }

    static Book GetBookFromDB(int id)
    {
        //simulate some database access

        return new Book { Id = id,
                          Title = "Book" + id,
                          Author = "Author" + id };
    }
}
				  
Other  
  •  D-Link Cloud Router 5700 With 1750Mbps Total Band
  •  The HP Virtual Server Environment : Virtual Partitions (Peak Performance Virtualization)
  •  The HP Virtual Server Environment : nPartitions (Electrically Isolated Hardware Partitions)
  •  The HP Virtual Server Environment : The Partitioning Continuum at a Glance
  •  IBM WebSphere Process Server 7 and Enterprise Service Bus 7 : Monitoring WPS/WESB applications
  •  Microsoft Dynamics Sure Step 2010 : The Microsoft Solution Selling Process
  •  Microsoft Dynamics Sure Step 2010 : Solution selling concepts
  •  Microsoft Dynamics Sure Step 2010 : Driving value for the customer and the solution provider
  •  Active Directory Domain Services 2008 : Delegate Permissions for WMI Filters
  •  Active Directory Domain Services 2008 : Delegate Permissions for Generating Group Policy Results
  •  
    Most View
    The Excellent EVGA Card - PNY GTX 780 Ti XlR8
    Introducing Windows Presentation Foundation and XAML : Building WPF Applications Using Visual Studio 2010 (part 2)
    The Cat You Have To Have (Part 2)
    Samsung Galaxy Camera VS The Rest (Part 5)
    SQL Server 2012 : SQL Server Security Overview
    Windows Server 2008 R2 networking : Planning and Deploying DNS (part 3) - Setting up DNS zones
    Integrated Amplifier : Ayre AX-5 (Part 1)
    Nikon Coolpix S9400 Review – Camera Rich Of Features (Part 1)
    What To Do When Your PC Is Slow (Part 1)
    SQL Server 2005 : Working with SQL Server Management Objects in Visual Studio (part 3) - Creating Backup-and-Restore Applications, Performing Programmatic DBCC Commands with SMO
    Top 10
    SQL Server 2012 : Policy Based Management - Evaluating Policies
    SQL Server 2012 : Defining Policies (part 3) - Creating Policies
    SQL Server 2012 : Defining Policies (part 2) - Conditions
    SQL Server 2012 : Defining Policies (part 1) - Management Facets
    Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 4) - Preventing Internal Servers from Being Filtered
    Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 3) - Defining Block List Exceptions and Global Allow/Block Lists
    Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 2) - Filtering Connections with IP Block Lists
    Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 1) - Filtering Spam and Other Unwanted E-Mail by Sender, Filtering Spam and Other Unwanted E-Mail by Recipien
    Microsoft Exchange Server 2010 : Creating and Managing Remote Domains (part 3) - Configuring Messaging Options for Remote Domains , Removing Remote Domains
    Microsoft Exchange Server 2010 : Creating and Managing Remote Domains (part 2) - Creating Remote Domains