diff --git a/akka-actor/src/main/scala/akka/io/DirectByteBufferPool.scala b/akka-actor/src/main/scala/akka/io/DirectByteBufferPool.scala index 7b535c96e4..eb0e583f2d 100644 --- a/akka-actor/src/main/scala/akka/io/DirectByteBufferPool.scala +++ b/akka-actor/src/main/scala/akka/io/DirectByteBufferPool.scala @@ -19,8 +19,12 @@ trait BufferPool { * A buffer pool which keeps a free list of direct buffers of a specified default * size in a simple fixed size stack. * - * If the stack is full a buffer offered back is not kept but will be let for - * being freed by normal garbage collection. + * If the stack is full the buffer is de-referenced and available to be + * freed by normal garbage collection. + * + * Using a direct ByteBuffer when dealing with NIO operations has been proven + * to be faster than wrapping on-heap Arrays. There is ultimately no performance + * benefit to wrapping in-heap JVM data when writing with NIO. */ private[akka] class DirectByteBufferPool(defaultBufferSize: Int, maxPoolEntries: Int) extends BufferPool { private[this] val locked = new AtomicBoolean(false) diff --git a/akka-actor/src/main/scala/akka/util/ByteString.scala b/akka-actor/src/main/scala/akka/util/ByteString.scala index 37a3d9ca2d..5a1bbb3e74 100644 --- a/akka-actor/src/main/scala/akka/util/ByteString.scala +++ b/akka-actor/src/main/scala/akka/util/ByteString.scala @@ -544,8 +544,10 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { _tempCapacity = _temp.length } + @inline private def shouldResizeTempFor(size: Int): Boolean = _tempCapacity < size || _tempCapacity == 0 + private def ensureTempSize(size: Int): Unit = { - if (_tempCapacity < size || _tempCapacity == 0) { + if (shouldResizeTempFor(size)) { var newSize = if (_tempCapacity == 0) 16 else _tempCapacity * 2 while (newSize < size) newSize *= 2 resizeTemp(newSize) @@ -576,6 +578,13 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { _length += bs.length case xs: WrappedArray.ofByte ⇒ putByteArrayUnsafe(xs.array.clone) + case seq: collection.IndexedSeq[Byte] if shouldResizeTempFor(seq.length) ⇒ + val copied = new Array[Byte](seq.length) + seq.copyToArray(copied) + + clearTemp() + _builder += ByteString.ByteString1(copied) + _length += seq.length case seq: collection.IndexedSeq[_] ⇒ ensureTempSize(_tempLength + xs.size) xs.copyToArray(_temp, _tempLength)