Resource Pooling |
The DigitalRune Base library provides a general implementation of a resource pool. This section explains the concept of a resource pool and why it is necessary.
This topic contains the following sections:
The current version of the .NET Compact Framework has some limitations compared to the full version of the .NET Framework. In particular, it does not support generational garbage collection. A run of the garbage collector on the Xbox 360 or on the Windows Phone 7 typically has a higher latency than in Windows and can lead to significant frame rate drops.
Therefore, it is crucial to reduce the amount of memory that is allocated at runtime to avoid too frequent garbage collections. A strategy to reduce memory allocations is resource pooling (or free-lists). When using a resource pool objects are acquired from the pool instead of being newly allocated on the managed heap. When an object is no longer used it is returned to the resource pool for later reuse.
The DigitalRune Base library contains a general implementation of a resource pool: see ResourcePoolT. Other DigitalRune projects, such as DigitalRune Geometry and Physics, make extensive use of this class. For example, the collision detection in DigitalRune Geometry creates and removes contacts every frame. The type that stores the contact information is reused using a resource pool to minimize the number of newly allocated objects.
Here is an example how to create a resource pool for an object of type ObjectXyz:
ResourcePool<ObjectXyz> Pool = new ResourcePool<ObjectXyz>( () => new ObjectXyz(), // Create the object. obj => obj.Initialize(), // Initialize the object. (Optional) obj => obj.Uninitialize()); // Uninitialize the object. (Optional)
The constructor of the ResourcePoolT requires 3 parameters: A create callback, an initialize callback and an uninitialize callback. In the example above the callbacks are implemented using lambda expressions. The initialize and the uninitialize callbacks are optional. (The last two parameters can be null.)
Using this resource pool objects of the given type can be obtained when needed and recycled after use:
var obj = Pool.Obtain(); // Do something with the object. ... // Return the object to the resource pool when no longer needed. Pool.Recycle(obj); obj = null;
Resource pools are initially empty. New objects are created on demand – so a resource pool never runs out of objects.
By consistently using the resource pool and the Obtain/Recycle pattern throughout the application unnecessary garbage can be avoided.
In some situations we temporarily need a collection of a certain type (e.g. a List<T>). It is not necessary to manually create a new resource pool for every type T. The static class ResourcePoolsT provides resource pools for common types of collections (lists, hash-sets, stacks).
Here is an example that shows how to obtain a List<float> from the global resource pool.
// Obtain an empty list from the global resource pool. List<float> list = ResourcePools<float>.Lists.Obtain(); // Do something with the list. ... // After use, recycle the list. (Note: It is not necessary to clear the // list before recycling. This is handled automatically.) ResourcePools<float>.Lists.Recycle(list);
The implementation of ResourcePoolT is thread-safe. Multiple threads can simultaneously obtain/recycle objects from the same resource pool.
Additionally, the current implementation is lock free – for the most parts. Locks can be expensive, we therefore tried to avoid locks whenever possible for optimal performance. (Internally, all threads have a local resource pool to prevent contention when multiple threads need to access the same resource. If one thread’s local pool is empty it tries to steal resources from another thread. But users don’t have to worry about these internals.)
The base class ResourcePool provides global control over all resource pools. For example,