String.charAt vs StringBuilder.charAt performance
Chen Liang
liangchenblue at gmail.com
Sat Jul 19 21:17:24 UTC 2025
Without looking at C2 IRs, I think there are a few potential culprits we
can look into:
1. JDK-8351000 and JDK-8351443 updated StringBuilder
2. Sequence field is read in the loop; I wonder if making it an explicit
immutable local variable changes anything here.
On Sat, Jul 19, 2025 at 2:34 PM Brett Okken <brett.okken.os at gmail.com>
wrote:
> I was looking at the performance of StringCharBuffer for various
> backing CharSequence types and was surprised to see a significant
> performance difference between String and StringBuffer. I wrote a
> small jmh which shows that the String implementation of charAt is
> significantly slower than StringBuilder. Is this expected?
>
> Benchmark (data) (source) Mode Cnt
> Score Error Units
> CharSequenceCharAtBenchmark.test ascii String avgt 3
> 2537.311 ┬▒ 8952.197 ns/op
> CharSequenceCharAtBenchmark.test ascii StringBuffer avgt 3
> 852.004 ┬▒ 2532.958 ns/op
> CharSequenceCharAtBenchmark.test non-ascii String avgt 3
> 5115.381 ┬▒ 13822.592 ns/op
> CharSequenceCharAtBenchmark.test non-ascii StringBuffer avgt 3
> 836.230 ┬▒ 1154.191 ns/op
>
>
>
> @Measurement(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS)
> @Warmup(iterations = 2, time = 7, timeUnit = TimeUnit.SECONDS)
> @BenchmarkMode(Mode.AverageTime)
> @OutputTimeUnit(TimeUnit.NANOSECONDS)
> @State(Scope.Benchmark)
> @Fork(value = 1, jvmArgsPrepend = {"-Xms512M", "-Xmx512M"})
> public class CharSequenceCharAtBenchmark {
>
> @Param(value = {"ascii", "non-ascii"})
> public String data;
>
> @Param(value = {"String", "StringBuffer"})
> public String source;
>
> private CharSequence sequence;
>
> @Setup(Level.Trial)
> public void setup() throws Exception {
> StringBuilder sb = new StringBuilder(3152);
> for (int i=0; i<3152; ++i) {
> char c = (char) i;
> if ("ascii".equals(data)) {
> c = (char) (i & 0x7f);
> }
> sb.append(c);
> }
>
> switch(source) {
> case "String":
> sequence = sb.toString();
> break;
> case "StringBuffer":
> sequence = sb;
> break;
> default:
> throw new IllegalArgumentException(source);
> }
> }
>
> @Benchmark
> public int test() {
> int sum = 0;
> for (int i=0, j=sequence.length(); i<j; ++i) {
> sum += sequence.charAt(i);
> }
> return sum;
> }
> }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20250719/e0eb342f/attachment-0001.htm>
More information about the core-libs-dev
mailing list