Sorry, there is no magic solution here. The best suggestions I have are either:
1) Use SerializeToString() instead, which will always allocate a string large enough to hold the message.
2) Build your message, then call ByteSize(), and if it is too large, remove some fields and try again. Once it is big enough, call SerializeWithCachedSizesToArray() -- since you already called ByteSize(), the sizes are already cached. This way, if the message fits on the first attempt, you perform just as well as you did before, because SerializeToArray() calls ByteSize() followed by SerializeWithCachedSizesToArray().