Blog

DigitalRune Helper Library: Resource Pooling in XNA (Part 1)

Mar 2

Written by:
Wednesday, March 02, 2011  RssIcon


By now, we probably all know that the latency of the garbage collector on Xbox 360 and Windows Phone 7 can be a problem. One solution is to avoid frequent memory allocations by using resource pools (or free-lists).

This blog post provides some information about the resource pool implementation provided by the DigitalRune libraries.

DigitalRune.ResourcePool<T>

The DigitalRune Helper library contains a general implementation of a resource pool: ResourcePool<T>. The projects 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 ResourcePool<T> 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.

Pools for Generic Collections

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 ResourcePools<T> provides resource pools for common types of collections (Lists, Hashsets, 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);

Thread-Safety

The latest update of DigitalRune Geometry and Physics added support for multithreading. For example: By default, all collision checks in collision domain are computed in parallel. Most collision algorithms require temporary objects that are taken from internal resource pools. Therefore, it was crucial to make all resource pools thread-safe.

The implementation of ResourcePool<T> 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.)

Global Control

The base class ResourcePool provides global control over all resource pools. For example,

  • By setting ResourcePool.Enabled to false, resource pooling can be disabled in the entire application. (The property is true by default.)
  • ResourcePool.ClearAll() can be called to clear all resource pools in the application. This is useful because different parts of a game might have a different memory usage. One level might be very physics intensive and thereby fill up the resource pools of the physics simulations. The next level might be very graphics intensive and fill up other resource pools. It can be useful to clear all resource pools when loading a new level to start with a clean memory. In particular, if you ever call GC.Collect() manually, you should consider calling ResourcePool.ClearAll() before you invoke the garbage collector. (Note that you can also clear individual pools by calling ResourcePool<T>.Clear().)
  • ResourcePool.Pools is a collection containing all active resource pools of the application. This property might be useful during debugging to observe memory usage. (Resource pools are automatically registered. Internally the resource pools are stored using weak reference. So you do not need to worry that obsolete resource pools are accidentally kept alive.)

Conclusion

Our implementation of a resource pool is not just intended for internal use by the DigitalRune libraries. We encourage you to use it in your own code. It is thoroughly tested and has proven useful in many situations. If you find it helpful, we’d like to hear your feedback.

But before you start adding resource pools for all game objects, never forget the 10 rules of performance:

“Measure, measure, measure, … (repeated 10 times)!” (Quote: Rico Mariani)


Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel