Skip to content

Instantly share code, notes, and snippets.

@PhilipRoman
Last active April 21, 2018 13:29
Show Gist options
  • Save PhilipRoman/a2f3e1ac63280d1d1793588029919769 to your computer and use it in GitHub Desktop.
Save PhilipRoman/a2f3e1ac63280d1d1793588029919769 to your computer and use it in GitHub Desktop.
Java performance anomaly: the loop with 'beta' method is 2x slower than loop with 'alpha' even though the methods are identical.
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
public class Main {
private static final int N = 1_000_000;
private static Field stringBytes;
private static String testString;
static {
// setup test string:
StringBuilder builder = new StringBuilder(1024);
for (int i = 0; i < 100; i++) {
builder.append("Hello, world!");
}
testString = builder.toString();
// setup String byte array field:
try {
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringBytes = stringValue;
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IllegalAccessException {
ByteBuffer expectedBuffer = ByteBuffer.allocate(2000)
.put(testString.getBytes());
ByteBuffer testBuffer = ByteBuffer.allocate(2000);
//
for (int i = 0; i < 10; i++) {
runTests(testBuffer, expectedBuffer);
}
}
private static void runTests(ByteBuffer testBuffer, ByteBuffer expectedBuffer) throws
IllegalAccessException {
long startTime = System.nanoTime();
for (int i = 0; i < N; i++) {
testBuffer.clear();
slow(testBuffer);
checkResult(testBuffer, expectedBuffer);
}
long endTime = System.nanoTime();
System.out.println("Slow: \t" + (endTime - startTime));
//
startTime = System.nanoTime();
for (int i = 0; i < N; i++) {
testBuffer.clear();
alpha(testBuffer);
checkResult(testBuffer, expectedBuffer);
}
endTime = System.nanoTime();
System.out.println("Alpha: \t" + (endTime - startTime));
//
startTime = System.nanoTime();
for (int i = 0; i < N; i++) {
testBuffer.clear();
beta(testBuffer);
checkResult(testBuffer, expectedBuffer);
}
endTime = System.nanoTime();
System.out.println("Beta: \t" + (endTime - startTime));
}
// make sure the JIT doesn't discard computations
private static void checkResult(ByteBuffer got, ByteBuffer expected) {
if (!got.equals(expected)) {
throw new RuntimeException(
String.format("expected: %s, got %s", expected, got)
);
}
}
private static void slow(ByteBuffer source) {
source.put(testString.getBytes());
}
private static void alpha(ByteBuffer source) throws IllegalAccessException {
source.put((byte[]) stringBytes.get(testString));
}
private static void beta(ByteBuffer source) throws IllegalAccessException {
source.put((byte[]) stringBytes.get(testString));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment