Use object pooling of byte arrays to prevent heap fragmentation in socket applications


When you are worrking on managed socket application and your application is very extensively doing send/recieve on the socket, then probably you need to care about understanding the heap management. Socket.Recieve or Socket.Send finally need to call the underlying native winsock API call to recieve the data on user specified buffer. Same is true for NetworkStream.Read and NetworkStream.Write calls, because these methods also finally got translated socket send and recieve.


To make the native API call buffer need to pinned for I/O, these pinned buffer can not be moved when garbage collector is doing the work of cleaning up. If your application is using newly allocated buffer in slow network environment and application is doing multiple I/O call frequently then it is possible that you will hit the problem of heap fragmentation. If fragmentation is small, you probably do not need to worry about it, but if heap fragmentation is reaching more than 10% and you are seeing larger time spend on GC. You need to look into some better techniques to elliminate the unnecessary pressure on GC. One possible solution is create a pool of buffer in the startup and use object pooiling to reuse them as needed.


Check the maoni’s blog entry Using GC Efficiently – Part 3 to understand more about pinning and effective usage of GC and other good tips.


This posting is provided “AS IS” with no warranties, and confers no rights

Comments (3)

  1. s*****r says:

    Hi,

    This one is good .but i want to implement socketpooling by using hashtables explicitly.

    can u plz give me some idea how it can be

  2. jamesdbrock says:

    Hi Adarsh,

    I’ve written a high-performance synchronous network application in C#, CLR 2.0. This application needs to receive ~300,000 UDP datagrams/second, and I find that its performance is CPU-bound. At run-time, the application spends about 70% of its time in privileged kernel mode. (There are no locks or P/Invoke or anything else which could be causing the thread to transition to kernel mode). Is this unavoidable overhead of using System.Net.Sockets.Socket?

    From your post, I see that Socket pins the receive buffer so that Winsock2 can write to it… that’s a relief. I was afraid that Socket copied the whole buffer from the non-paged pool into the managed heap.

    I am considering re-writing my network assemblies in C++/CLI, and dealing directly with Winsock2. My idea that I would see a performance improvement if I can supply a native array for a receive buffer, then parse messages directly on to the CLR thread stack, bypassing the managed heap entirely. Is that a good idea?

    Regards,

    James Brock

  3. Kevin English says:

    Chris Mullins gave a specific work around to this issue at:

    http://bytes.com/forum/thread561777.html

    «

    By deriving a class from NetworkStream and overring the relevant methods, we can swap out the buffers used by SSLStream with our own buffers. Because our

    buffers come from a bufferpool that’s allocated in a way to minimize heap fragmentation, the heap stays unfragmented, and scalability is largely unaffected

    »