Trying to get to the bottom of an OutOfMemoryException I found that .net\'s BufferManagers, used by WCF\'s buffered TransferMode, were responsible for wasting literally hund
I recently worked on a Proxy service which accepted multiple client connections (upto 500 simultaneous connections). The Proxy relayed client requests to the destination server and relayed back responses from destination servers to the clients. The proxy service used Byte arrays (Byte[]) as buffers to send and receive data. I had no Buffer Manager in place.
The proxy was creating a new byte array every time to send and receive data from socket. The private bytes in the resource monitor kept increasing. Running ANT Memory Profiler tool showed large fragments which kept increasing.
The solution was to implement a simple Buffermanager class to manage the memory used by the Buffers. Here is the code snippet
public class BufferManager
{
private readonly int m_ByteSize;
private readonly Stack<byte[]> m_Buffers;
private readonly object m_LockObject = new Object();
#region constructors
public BufferManager(int _byteSize, int _poolCount)
{
lock (m_LockObject)
{
m_ByteSize = _byteSize;
m_Buffers = new Stack<Byte[]>(_poolCount);
for (int i = 0; i < _poolCount; i++)
{
CreateNewSegment();
}
}
}
#endregion //constructors
public int AvailableBuffers
{
get { return m_Buffers.Count; }
}
public System.Int64 TotalBufferSizeInBytes
{
get { return m_Buffers.Count * m_ByteSize; }
}
public System.Int64 TotalBufferSizeInKBs
{
get { return (m_Buffers.Count * m_ByteSize/1000); }
}
public System.Int64 TotalBufferSizeInMBs
{
get { return (m_Buffers.Count * m_ByteSize/1000000); }
}
private void CreateNewSegment()
{
byte[] bytes = new byte[m_ByteSize];
m_Buffers.Push(bytes);
}
/// <summary>
/// Checks out a buffer from the manager
/// </summary>
public Byte[] CheckOut()
{
lock (m_LockObject)
{
if (m_Buffers.Count == 0)
{
CreateNewSegment();
}
return m_Buffers.Pop();
}
}
/// <summary>
/// Returns a buffer to the control of the manager
/// </summary>
///<remarks>
/// It is the client’s responsibility to return the buffer to the manger by
/// calling Checkin on the buffer
///</remarks>
public void CheckIn(Byte[] _Buffer)
{
lock (m_LockObject)
{
m_Buffers.Push(_Buffer);
}
}
}