AnswerStopping the leaks

time to read 6 min | 1068 words

Originally posted at 4/19/2011

Yesterday I posted the following challenge:

Given the following API, can you think of a way that would prevent memory leaks?

public interface IBufferPool
    byte[] TakeBuffer(int size);
    void ReturnBuffer(byte[] buffer);

The problem with having something like this is that forgetting to return the buffer is going to cause a memory leak. Instead of having that I would like to have the application stop if a buffer is leaked. Leaked means that no one is referencing this buffer but it wasn’t returned to the pool.

What I would really like is that when running in debug mode, leaking a buffer would stop the entire application and tell me:

  • That a buffer was leaked.
  • What was the stack trace that allocated that buffer.

Let us take a look at how we are going about implementing this, shall we? I am going to defer the actual implementation of the buffer pool to System.ServiceModel.Channels.BufferManager and focus on providing the anti leak features. The result is that this code:

IBufferPool pool = new BufferPool(1024*512, 1024);

var buffer = pool.TakeBuffer(512);
GC.WaitForPendingFinalizers(); // nothing here

buffer = null;
GC.WaitForPendingFinalizers(); // nothing here, we released the memory properly

pool.TakeBuffer(512); // take and discard a buffer without returning to the pool
GC.WaitForPendingFinalizers(); // failure!

Will result in the following error:

Unhandled Exception: System.InvalidOperationException: A buffer was leaked. Initial allocation:
   at ConsoleApplication1.BufferPool.BufferTracker.TrackAllocation() in IBufferPool.cs:line 22
   at ConsoleApplication1.BufferPool.TakeBuffer(Int32 size) in IBufferPool.cs:line 60
   at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 21

And now for the implementation:

public class BufferPool : IBufferPool
    public class BufferTracker
        private StackTrace stackTrace;

        public void TrackAllocation()
            stackTrace = new StackTrace(true);

        public void Discard()
            stackTrace = null;

            if (stackTrace == null)

            throw new InvalidOperationException(
                "A buffer was leaked. Initial allocation:" + Environment.NewLine + stackTrace

    private readonly BufferManager bufferManager;
    private ConditionalWeakTable<byte[], BufferTracker> trackLeakedBuffers = new ConditionalWeakTable<byte[], BufferTracker>();

    public BufferPool(long maxBufferPoolSize, int maxBufferSize)
        bufferManager = BufferManager.CreateBufferManager(maxBufferPoolSize, maxBufferSize);

    public void Dispose()
        // note that disposing the pool before returning all of the buffers will cause a crash

    public byte[] TakeBuffer(int size)
        var buffer = bufferManager.TakeBuffer(size);
        return buffer;

    public void ReturnBuffer(byte[] buffer)
        BufferTracker value;
        if(trackLeakedBuffers.TryGetValue(buffer, out value))

As you can see, utilizing ConditionalWeakTable is quite powerful, since it allows us to support a lot of really advanced scenarios in a fairly simple ways.

More posts in "Answer" series:

  1. (07 Apr 2022) Why is this code broken?
  2. (20 Jan 2017) What does this code do?
  3. (16 Aug 2011) Modifying execution approaches
  4. (30 Apr 2011) Stopping the leaks
  5. (24 Dec 2010) This code should never hit production
  6. (21 Dec 2010) Your own ThreadLocal
  7. (11 Feb 2010) Debugging a resource leak
  8. (03 Sep 2009) The lazy loaded inheritance many to one association OR/M conundrum
  9. (04 Sep 2008) Don't stop with the first DSL abstraction
  10. (12 Jun 2008) How many tests?