optimize number of buffer allocations (#11879) · grpc/grpc-java@5a7f350
@@ -75,6 +75,10 @@ void deliverFrame(
7575// effectively final. Can only be set once.
7676private int maxOutboundMessageSize = NO_MAX_OUTBOUND_MESSAGE_SIZE;
7777private WritableBuffer buffer;
78+/**
79+ * if > 0 - the number of bytes to allocate for the current known-length message.
80+ */
81+private int knownLengthPendingAllocation;
7882private Compressor compressor = Codec.Identity.NONE;
7983private boolean messageCompression = true;
8084private final OutputStreamAdapter outputStreamAdapter = new OutputStreamAdapter();
@@ -222,9 +226,7 @@ private int writeKnownLengthUncompressed(InputStream message, int messageLength)
222226headerScratch.put(UNCOMPRESSED).putInt(messageLength);
223227// Allocate the initial buffer chunk based on frame header + payload length.
224228// Note that the allocator may allocate a buffer larger or smaller than this length
225-if (buffer == null) {
226-buffer = bufferAllocator.allocate(headerScratch.position() + messageLength);
227- }
229+knownLengthPendingAllocation = HEADER_LENGTH + messageLength;
228230writeRaw(headerScratch.array(), 0, headerScratch.position());
229231return writeToOutputStream(message, outputStreamAdapter);
230232 }
@@ -288,8 +290,9 @@ private void writeRaw(byte[] b, int off, int len) {
288290commitToSink(false, false);
289291 }
290292if (buffer == null) {
291-// Request a buffer allocation using the message length as a hint.
292-buffer = bufferAllocator.allocate(len);
293+checkState(knownLengthPendingAllocation > 0, "knownLengthPendingAllocation reached 0");
294+buffer = bufferAllocator.allocate(knownLengthPendingAllocation);
295+knownLengthPendingAllocation -= min(knownLengthPendingAllocation, buffer.writableBytes());
293296 }
294297int toWrite = min(len, buffer.writableBytes());
295298buffer.write(b, off, toWrite);
@@ -388,6 +391,8 @@ public void write(byte[] b, int off, int len) {
388391 * {@link OutputStream}.
389392 */
390393private final class BufferChainOutputStream extends OutputStream {
394+private static final int FIRST_BUFFER_SIZE = 4096;
395+391396private final List<WritableBuffer> bufferList = new ArrayList<>();
392397private WritableBuffer current;
393398@@ -397,7 +402,7 @@ private final class BufferChainOutputStream extends OutputStream {
397402 * {@link #write(byte[], int, int)}.
398403 */
399404@Override
400-public void write(int b) throws IOException {
405+public void write(int b) {
401406if (current != null && current.writableBytes() > 0) {
402407current.write((byte)b);
403408return;
@@ -410,7 +415,7 @@ public void write(int b) throws IOException {
410415public void write(byte[] b, int off, int len) {
411416if (current == null) {
412417// Request len bytes initially from the allocator, it may give us more.
413-current = bufferAllocator.allocate(len);
418+current = bufferAllocator.allocate(Math.max(FIRST_BUFFER_SIZE, len));
414419bufferList.add(current);
415420 }
416421while (len > 0) {