Hello, while looking into an issue I've found out that scalar replacement is not working in trivial case on JDK 14.0.1.
This benchmark illustrates the issue: @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Fork(jvmArgsAppend = {"-Xms2g", "-Xmx2g"}) public class StringCompositeKeyBenchmark { @Benchmark public Object compositeKey(Data data) { return data.keyObjectMap.get(new Key(data.code, data.locale)); } @State(Scope.Thread) public static class Data { private final String code = "code1"; private final Locale locale = Locale.getDefault(); private final HashMap<Key, Object> keyObjectMap = new HashMap<>(); @Setup public void setUp() { keyObjectMap.put(new Key(code, locale), new Object()); } } private static final class Key { private final String code; private final Locale locale; private Key(String code, Locale locale) { this.code = code; this.locale = locale; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Key key = (Key) o; if (!code.equals(key.code)) return false; return locale.equals(key.locale); } @Override public int hashCode() { return 31 * code.hashCode() + locale.hashCode(); } } } When I run this on JDK 11 (JDK 11.0.7, OpenJDK 64-Bit Server VM, 11.0.7+10-post-Ubuntu-2ubuntu218.04) I get this output: Benchmark Mode Cnt Score Error Units StringCompositeKeyBenchmark.compositeKey avgt 10 5.510 ± 0.121 ns/op StringCompositeKeyBenchmark.compositeKey:·gc.alloc.rate avgt 10 ≈ 10⁻⁴ MB/sec StringCompositeKeyBenchmark.compositeKey:·gc.alloc.rate.norm avgt 10 ≈ 10⁻⁶ B/op StringCompositeKeyBenchmark.compositeKey:·gc.count avgt 10 ≈ 0 counts As I understand Java runtime erases object allocation here and we don't use additional memory. Same run on JDK 14 (JDK 14.0.1, Java HotSpot(TM) 64-Bit Server VM, 14.0.1+7) demonstrate object allocation per each method call: Benchmark Mode Cnt Score Error Units StringCompositeKeyBenchmark.compositeKey avgt 10 7.958 ± 1.360 ns/op StringCompositeKeyBenchmark.compositeKey:·gc.alloc.rate avgt 10 1937.551 ± 320.718 MB/sec StringCompositeKeyBenchmark.compositeKey:·gc.alloc.rate.norm avgt 10 24.001 ± 0.001 B/op StringCompositeKeyBenchmark.compositeKey:·gc.churn.G1_Eden_Space avgt 10 1879.111 ± 596.770 MB/sec StringCompositeKeyBenchmark.compositeKey:·gc.churn.G1_Eden_Space.norm avgt 10 23.244 ± 5.509 B/op StringCompositeKeyBenchmark.compositeKey:·gc.churn.G1_Survivor_Space avgt 10 0.267 ± 0.750 MB/sec StringCompositeKeyBenchmark.compositeKey:·gc.churn.G1_Survivor_Space.norm avgt 10 0.003 ± 0.009 B/op StringCompositeKeyBenchmark.compositeKey:·gc.count avgt 10 23.000 counts StringCompositeKeyBenchmark.compositeKey:·gc.time avgt 10 44.000 ms At the same time in more trivial scenario like @Benchmark public int compositeKey(Data data) { return new Key(data.code, data.locale).hashCode(); } scalar replacement again eliminates allocation of object. So I'm curious whether this is normal behaviour or a bug? Regards, Sergey Tsypanov