StringCreateBenchmark.java
package com.alibaba.fastjson2.benchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.lang.invoke.*;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import static com.alibaba.fastjson2.util.JDKUtils.UNSAFE;
public class StringCreateBenchmark {
static final BiFunction<char[], Boolean, String> STRING_CREATOR = getStringCreator();
static final char[] chars = new char[128];
static long valueOffset;
static {
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
valueOffset = UNSAFE.objectFieldOffset(field);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public static BiFunction<char[], Boolean, String> getStringCreator() {
try {
MethodHandles.Lookup caller = MethodHandles.lookup().in(String.class);
Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes");
modes.setAccessible(true);
modes.setInt(caller, -1); // -1 == Lookup.TRUSTED
// create handle for shared String constructor
MethodHandle handle = caller.findConstructor(
String.class,
MethodType.methodType(void.class, char[].class, boolean.class)
);
CallSite callSite = LambdaMetafactory.metafactory(
caller,
"apply",
MethodType.methodType(BiFunction.class),
handle.type().generic(),
handle,
handle.type()
);
return (BiFunction) callSite.getTarget().invokeExact();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Benchmark
public String creator() {
return STRING_CREATOR.apply(chars, Boolean.TRUE);
}
@Benchmark
public String newString() {
return new String(chars);
}
@Benchmark
public String unsafe() throws Exception {
String str = (String) UNSAFE.allocateInstance(String.class);
UNSAFE.putObject(str, valueOffset, chars);
return str;
}
public void creator_benchmark() {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000_000_000; i++) {
creator();
}
long millis = System.currentTimeMillis() - start;
System.out.println("creator : " + millis);
}
public void new_benchmark() throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000_000; i++) {
unsafe();
}
long millis = System.currentTimeMillis() - start;
System.out.println("new : " + millis);
}
// @Test
public void test_benchmark() throws Exception {
for (int i = 0; i < 10; i++) {
new_benchmark();
}
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(StringCreateBenchmark.class.getName())
.mode(Mode.Throughput)
.timeUnit(TimeUnit.MILLISECONDS)
.forks(1)
.build();
new Runner(options).run();
}
}