This is an automated email from the ASF dual-hosted git repository.
He-Pin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new 58a9bf0077 perf: use Arrays.copyOf/copyOfRange instead of manual new
Array + arraycopy (#3150)
58a9bf0077 is described below
commit 58a9bf0077872d7776d926dca01f287529d13df0
Author: He-Pin(kerr) <[email protected]>
AuthorDate: Tue Jun 23 18:43:47 2026 +0800
perf: use Arrays.copyOf/copyOfRange instead of manual new Array + arraycopy
(#3150)
* perf: use Arrays.copyOf/copyOfRange instead of manual new Array +
arraycopy
Motivation:
Several places allocate a new array then immediately copy from an
existing array using System.arraycopy. java.util.Arrays.copyOf and
copyOfRange combine allocation and copy in a single call that the JIT
can intrinsify more effectively.
Modification:
- ByteString.scala: 3 sites — clearTemp, resizeTemp, fromArray
replace new Array[Byte] + System.arraycopy with
java.util.Arrays.copyOf / copyOfRange
- ImmutableLongMap.scala: replace full array copy with values.clone()
- SnapshotSerializer.scala: replace partial copy with
java.util.Arrays.copyOfRange
Result:
Fewer lines, potentially faster due to JIT intrinsification of the
combined allocate+copy operation. ByteString builder operations
benefit most as they are in frequently-called paths.
Tests:
sbt "actor/compile" "remote/compile" "persistence/compile" — passed
References:
Refs #3136
* fix: guard Arrays.copyOf against null _temp in
ByteStringBuilder.resizeTemp
Motivation:
`ByteStringBuilder._temp` is initially `null` until the first call to
`++=` or `putByte`. `resizeTemp` was unconditionally calling
`java.util.Arrays.copyOf(_temp, size)` which throws
`NullPointerException` when passed a `null` source array. This bug was
introduced by the earlier "perf: use Arrays.copyOf/copyOfRange" commit
in the same PR, which replaced the previous `new Array[Byte](size)`
followed by `System.arraycopy(src, 0, dst, 0, n)` pattern — the old
pattern was safe because the arraycopy length was `0` when `_temp` was
`null`, masking the missing null check.
Modification:
Guard the call with `if (_temp eq null) new Array[Byte](size) else
java.util.Arrays.copyOf(_temp, size)`, so the first resize allocates a
fresh array and subsequent resizes retain the copyOf fast path.
Result:
`ByteStringBuilder` no longer throws NPE on the very first write when
the internal buffer has not yet been allocated.
Tests:
sbt "actor/compile" -- passed
sbt "actor-tests/Test/testOnly *ByteStringSpec" -- passed (relevant
directional tests; the NPE was also reachable from stream/Pekko usage).
References:
Discovered during internal review of PR #3150.
---
actor/src/main/scala/org/apache/pekko/util/ByteString.scala | 9 +++------
.../pekko/persistence/serialization/SnapshotSerializer.scala | 3 +--
.../scala/org/apache/pekko/remote/artery/ImmutableLongMap.scala | 3 +--
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
index 57c7762ef4..06d0162d50 100644
--- a/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
+++ b/actor/src/main/scala/org/apache/pekko/util/ByteString.scala
@@ -2728,8 +2728,7 @@ object CompactByteString {
val copyLength = Math.max(Math.min(array.length - copyOffset, length), 0)
if (copyLength == 0) empty
else {
- val copyArray = new Array[Byte](copyLength)
- System.arraycopy(array, copyOffset, copyArray, 0, copyLength)
+ val copyArray = java.util.Arrays.copyOfRange(array, copyOffset,
copyOffset + copyLength)
ByteString.ByteString1C(copyArray)
}
}
@@ -2789,16 +2788,14 @@ final class ByteStringBuilder extends Builder[Byte,
ByteString] {
private def clearTemp(): Unit = {
if (_tempLength > 0) {
- val arr = new Array[Byte](_tempLength)
- System.arraycopy(_temp, 0, arr, 0, _tempLength)
+ val arr = java.util.Arrays.copyOf(_temp, _tempLength)
_builder += ByteString1(arr)
_tempLength = 0
}
}
private def resizeTemp(size: Int): Unit = {
- val newtemp = new Array[Byte](size)
- if (_tempLength > 0) System.arraycopy(_temp, 0, newtemp, 0, _tempLength)
+ val newtemp = if (_temp eq null) new Array[Byte](size) else
java.util.Arrays.copyOf(_temp, size)
_temp = newtemp
_tempCapacity = _temp.length
}
diff --git
a/persistence/src/main/scala/org/apache/pekko/persistence/serialization/SnapshotSerializer.scala
b/persistence/src/main/scala/org/apache/pekko/persistence/serialization/SnapshotSerializer.scala
index d60b314a62..0e022575de 100644
---
a/persistence/src/main/scala/org/apache/pekko/persistence/serialization/SnapshotSerializer.scala
+++
b/persistence/src/main/scala/org/apache/pekko/persistence/serialization/SnapshotSerializer.scala
@@ -106,8 +106,7 @@ class SnapshotSerializer(val system: ExtendedActorSystem)
extends BaseSerializer
val manifest =
if (remaining == 0) ""
else {
- val manifestBytes = new Array[Byte](remaining)
- System.arraycopy(bytes, 4, manifestBytes, 0, remaining)
+ val manifestBytes = java.util.Arrays.copyOfRange(bytes, 4, 4 +
remaining)
migrateManifestToPekkoIfNecessary(new String(manifestBytes, UTF_8))
}
(serializerId, manifest)
diff --git
a/remote/src/main/scala/org/apache/pekko/remote/artery/ImmutableLongMap.scala
b/remote/src/main/scala/org/apache/pekko/remote/artery/ImmutableLongMap.scala
index 2b3d7f70ac..2d9eaa410f 100644
---
a/remote/src/main/scala/org/apache/pekko/remote/artery/ImmutableLongMap.scala
+++
b/remote/src/main/scala/org/apache/pekko/remote/artery/ImmutableLongMap.scala
@@ -69,8 +69,7 @@ private[pekko] class ImmutableLongMap[A >: Null] private
(private val keys: Arra
val i = Arrays.binarySearch(keys, key)
if (i >= 0) {
// existing key, replace value
- val newValues = new Array[A](values.length)
- System.arraycopy(values, 0, newValues, 0, values.length)
+ val newValues = values.clone()
newValues(i) = value
new ImmutableLongMap(keys, newValues)
} else {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]