Click or drag to resize

Reclamation and Cleanup

[This is preliminary documentation and is subject to change.]

Many implementations of interning suffer from the problem that they never clean up their pool of interned items (.NET's built-in string interning table is one example). The Condensed Library addresses this problem by offering several approaches to memory reclamation.

This topic contains the following sections:

Depending on your workload, you can choose one of the following options to clean up unused values in a CondensedCollection's intern pool.

Tip Tip

Use the CondensedCollection's InternPoolCount property to see the size of the intern pool--if it's larger than the UniqueCount property then your collection's pool contains unused values that can be reclaimed.

Option 1: Do nothing

Reasons not to worry about reclaiming items from the intern pool include:

  • You never modify the contents of the collection after initial load.

  • The collection gets modified, but the set of unique values you put in it is small and unchanging, so you don't need to worry about the intern pool containing unused values.

  • The collection gets modified, but the lifetime of the collection instance (or your application) is brief, so you don't care if some extra memory is consumed by the collection's intern pool.

Option 2: Periodically call CondensedCollection.Cleanup

The Cleanup method rebuilds the collection's internal data structures, removing unused values and making them eligible for garbage collection. This is a relatively expensive operation, so you may only want to perform it on an infrequent, periodic basis.

Note Note

The Cleanup method has no effect on collections that have cut over to normal (non-deduplicated) list storage. Reconstruct the collection from itself to rebuild it and restart deduplication (Option 3).

Option 3: Reconstruct

If you've constructed a CondensedCollection with the ability to cut over to non-deduplicated storage then the Cleanup() method will not be effective if/when your collection makes the transition. To restart deduplication, you can simply reconstruct a CondensedCollection from itself for a fresh start.

if (myCondensedColl.HasCutover)
{
    // Reconstruct collection from itself to restart deduplication.
    myCondensedColl = new CondensedCollection<string>(collection: myCondensedColl);
}
else
{
    // Do a normal cleanup:
    myCondensedColl.Cleanup();
}
Option 4: Cleanup from the InternedValueReclaimable Event (Preferred)

The CondensedCollection will raise the InternedValueReclaimable event as soon as one of the values in its pool is no longer used. You can set the InternReclaimableEventArgs.Cleanup property to true in your event handler to trigger a cleanup of the pool as soon as your handler completes.

A cleanup should not be performed every time this event is raised--the cleanup operation is very expensive, and it causes a full reindexing of the collection's internal data structures. Only set the InternReclaimableEventArgs.Cleanup property to true when the number of unused intern pool items exceeds your application's tolerances. The InternReclaimableEventArgs argument provides statistics about your collection to help you decide when a cleanup should be run.

A event handler that only performs occasional cleanup could be implemented as follows:

static void Main()
{
    var cc = new CondensedCollection<string>(comparer: StringComparer.Ordinal);
    cc.InternedValueReclaimable += HandleInternedValueReclaimable;   
}

static void HandleInternedValueReclaimable(object sender, InternReclaimableEventArgs e)
{
    // Perform cleanup as soon as we have 1000 unused strings in our intern pool.
    // After cleanup completes, those unused values will be eligible for garbage collection.
    if (e.ReclaimableInternsCount > 999)
        e.Cleanup = true;
}

The InternedValueReclaimable event will not be fired if the collection has cut over to a non-deduplicated list