The way we encode messages is a bit complex. We try not to allocate many buffers, but instead pre-compute the needed size, then allocate the buffer, and ultimately store the data.
It might be interesting to pre-allocate a buffer that is stored in the Thread Local Storage, big enough to store all the message, most of the time (like, a 4Kb buffer). As every encoding will be done in one single thread up to completion, this should never be problematic.
Another improvement, to avoid storing temporary information (like the bytes' length or the byte for Strings) would be to encode the messages by the end: Messages are TLV constructs, where the L gives some information about the V part. Usually, we know about the L when the V has been computed. If we start by flushing the V into the buffer, from the end, we can append the L before it, and so on. When done, we simply have to copy the whole data into the right sized buffer.
That would save a hell lot of allocations, thus GC cycles.
If the TLS buffer is not big enough, we simply compute the needed size, and encode the message the standard way.