From 83dc3b503ef692601a77f46c612c7e00bafd2336 Mon Sep 17 00:00:00 2001 From: Francesco Nigro Date: Thu, 11 Oct 2018 08:56:30 +0200 Subject: [PATCH] ByteBufInputStream is always allocating a StringBuilder instance (#8347) Motivation: Avoid creating any StringBuilder instance if ByteBufInputStream::readLine isn't used Modifications: The StringBuilder instance is lazy allocated on demand and are added new test case branches to address the increased complexity of ByteBufInputStream::readLine Result: Reduced GC activity if ByteBufInputStream::readLine isn't used --- .../io/netty/buffer/ByteBufInputStream.java | 25 ++++++++++++++++--- .../io/netty/buffer/ByteBufStreamTest.java | 6 +++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java b/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java index 2d8d34d323..b7b67d5408 100644 --- a/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java +++ b/buffer/src/main/java/io/netty/buffer/ByteBufInputStream.java @@ -16,6 +16,7 @@ package io.netty.buffer; import io.netty.util.ReferenceCounted; +import io.netty.util.internal.StringUtil; import java.io.DataInput; import java.io.DataInputStream; @@ -240,18 +241,23 @@ public class ByteBufInputStream extends InputStream implements DataInput { return buffer.readInt(); } - private final StringBuilder lineBuf = new StringBuilder(); + private StringBuilder lineBuf; @Override public String readLine() throws IOException { - lineBuf.setLength(0); + if (lineBuf != null) { + lineBuf.setLength(0); + } + + boolean anyChar = false; loop: while (true) { if (!buffer.isReadable()) { - return lineBuf.length() > 0 ? lineBuf.toString() : null; + return toStringIfAnyChar(lineBuf, anyChar); } int c = buffer.readUnsignedByte(); + anyChar = true; switch (c) { case '\n': break loop; @@ -263,11 +269,22 @@ public class ByteBufInputStream extends InputStream implements DataInput { break loop; default: + if (lineBuf == null) { + lineBuf = new StringBuilder(); + } lineBuf.append((char) c); } } - return lineBuf.toString(); + return lineBuf != null && lineBuf.length() > 0 ? lineBuf.toString() : StringUtil.EMPTY_STRING; + } + + private static String toStringIfAnyChar(StringBuilder lineBuf, boolean anyChars) { + if (anyChars) { + return lineBuf != null && lineBuf.length() > 0 ? lineBuf.toString() : StringUtil.EMPTY_STRING; + } else { + return null; + } } @Override diff --git a/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java b/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java index f05594d1c1..222ddcf7ee 100644 --- a/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java +++ b/buffer/src/test/java/io/netty/buffer/ByteBufStreamTest.java @@ -188,11 +188,13 @@ public class ByteBufStreamTest { String s = in.readLine(); assertNull(s); - int charCount = 5; //total chars in the string below without new line characters - byte[] abc = "a\nb\r\nc\nd\ne".getBytes(utf8); + int charCount = 7; //total chars in the string below without new line characters + byte[] abc = "\na\n\nb\r\nc\nd\ne".getBytes(utf8); buf.writeBytes(abc); in.mark(charCount); + assertEquals("", in.readLine()); assertEquals("a", in.readLine()); + assertEquals("", in.readLine()); assertEquals("b", in.readLine()); assertEquals("c", in.readLine()); assertEquals("d", in.readLine());