Show / Hide Table of Contents

Buffer Manager

On .Net Framework (4.0 and above) and .Net Core, the library supports buffer pooling to reduce allocation and improve performance.

IBufferManager

Application can implement this interface to manage byte array allocation and pooling. There are different pooling strategies.

  • Allocate fixed-size byte[] objects and create smaller pools of each size.
  • Allocate a large byte array and manage it like a heap.

The library provides a built-in buffer manager (BufferManager) which should be sufficient for most scenarios. If the application has a buffer manager for application data, it makes sense to use it as well for the library.

The buffer manager can be set to ConnectionFactory.BufferManager or ConnectionListener.BufferManager. Once it is set, most if not all byte array allocations will be through the buffer manager.

ConnectionFactory factory = new ConnectionFactory();
factory.BufferManager = new BufferManager(64, 1024 * 1024, 50 * 1024 * 1024);

In this example, a buffer manager is created to pool buffers from 64 bytes to 1 MB with a limit of 50 MB on total memory usage.

Application Responsibility

Sending Messages

In most cases, no special actions are required for sending messages. However, if the application has a lot of binary data to transfer, it should take advantage of Data.Buffer to reduce allocation. Data.Buffer is of type ByteBuffer which can wrap an existing byte[] or ArraySegment<byte> which in turn can be taken from the buffer manager. The following example shows how to use pooled buffers to initialize message for send.

ArraySegment<byte> segment = bufferManager.TakeBuffer(1024);
int len = WriteBuffer(segment);  // initialize the buffer and return payload length
ByteBuffer buffer = new ByteBuffer(segment.Array, segment.Offset, len, segment.Count);
Message message = new Message() { BodySection = new Data() { Buffer = buffer } };
try
{
    await sender.SendAsync(message);
}
finally
{
    bufferManager.ReturnBuffer(segment);
}

Receiving Messages

The received message is backed up by a buffer taken from the buffer manager. The ownership of the message is transferred to the application after the receive call. Therefore, the application must ensure that Message.Dispose is called after the message is processed, otherwise a buffer is leaked (not returned to the buffer manager). To access the message body, the application should avoid reading Message.Body or ((Data)Message.BodySection).Binary. Internally the library wraps the body payload in a ByteBuffer object, and it requires an allocation of byte[] with the exact size and a copy of the payload into the byte[] object. The recommended way to access the body is to get back the ByteBuffer object and process it as follows.

Message message = await receiver.ReceiveAsync();
try
{
    ByteBuffer buffer = message.GetBody<ByteBuffer>();
    await ProcessBufferAsync(buffer);
    receiver.Accept(message);
}
finally
{
    message.Dispose();
}
Back to top Copyright © 2015-2017 Microsoft
Generated by DocFX