私は最近、複数のクライアント接続 (最大 500 の同時接続) を受け入れるプロキシ サービスに取り組みました。プロキシは、クライアントの要求を宛先サーバーに中継し、宛先サーバーからの応答をクライアントに中継しました。プロキシ サービスは、Byte 配列 (Byte[]) をバッファとして使用してデータを送受信しました。Buffer Manager が配置されていませんでした。
プロキシは、ソケットからデータを送受信するたびに新しいバイト配列を作成していました。リソース モニターのプライベート バイトが増加し続けました。ANT Memory Profiler ツールを実行すると、大きなフラグメントが増え続けていることがわかりました。
解決策は、バッファによって使用されるメモリを管理する単純な Buffermanager クラスを実装することでした。ここにコードスニペットがあります
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);
}
}
}