In order for a Transport to read and write Messages, it may buffer the serialized message. At the very least, the Headers need to be buffered. And in many cases (such as to avoid head of the line blocking issues), buffering the entire message is necessary.
While the CLR’s garbage collector does a really good job of recycling memory, there are still costs involved with each allocation. These costs include zeroing out the buffer, as well as the GC churn. As our performance dev says “no work is better than some work”. A bunch of Indigo R & D has gone into creating an efficient way to pool buffers given two knobs:
- MaxBufferPoolSize – the total number of bytes to pool
- MaxItemSize – maximum size of an item stored in the pool
With proper tuning, large (>10%) increases in performance can be witnessed. This functionality is exposed through System.ServiceModel.Channels.BufferManager
. If you are writing a custom channel, you can create a BufferManager through the static method:
BufferManager
.CreateBufferManager(long
maxBufferPoolSize, int
maxSize)Then instead of calling “new
byte[n];
“, you can call “bufferManager.TakeBuffer(n);
“. Just remember to call bufferManager.ReturnBuffer(buffer)
(in a finally
block if necessary) when you are finished. Lastly, you can call bufferManager.Clear();
if you ever want to flush the cache (e.g. after a certain amount of idle time).
On the built-in WCF Bindings and Transport Binding Elements, we expose MaxBufferPoolSize as a property for you to control our cache footprint. If you are sending small (< 64K) messages, then the default value of 512K is likely acceptable. For larger messages, it's often best to avoid pooling altogether, which you can accomplish by setting MaxBufferPoolSize=0. You should of course profile your code under different values to determine the settings that will be optimal for your application.
Pingback: kennyw.com » Blog Archive » TcpTransport’s Buffer Management in WCF
Thanks, I have been searching and flogging my WCF app for quite a while to work out why it was consuming too much memory, and it turned out MaxBufferPoolSize was the answer, I was setting this way too big (having been ignorant of what it was when originally configuring things). With big messages (~2MB) this was a total disaster for the large object heap which, with heavy usage, ends up getting very out of hand.
Thanks!
Can you explain why it can be better to avoid pooling for large messages please?
For large messages, GC is more efficient
Pingback: Efficient Buffer management – Reduced LOH allocation | MSDN Blogs
thanks for nice article. It has solved my problem as i was getting an “The size necessary to buffer the XML content exceeded the buffer quota.”
thanks again