Skip to content

Instantly share code, notes, and snippets.

@hugmanrique
Last active July 24, 2021 22:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hugmanrique/948b9a17f25111f74516541eadaa0fba to your computer and use it in GitHub Desktop.
Save hugmanrique/948b9a17f25111f74516541eadaa0fba to your computer and use it in GitHub Desktop.
public enum BooleanFieldEnum {
// 2000 enum constants
private final boolean set;
BooleanFieldEnum() {
// Compute value on class loading, doesn't affect benchmark results
this.set = ThreadLocalRandom.current().nextBoolean();
}
public boolean isSet() {
return set;
}
}

BooleanFieldEnum has 2000 enum constants with a boolean field each (initialized on constructor). The isSet returns the value of this field.

SwitchEnum has 2000 enum constants with no fields. The isSet method does a switch on this (referring to the enum instance).

Test setup

# JMH version: 1.21
# VM version: JDK 11.0.2, Java HotSpot(TM) 64-Bit Server VM, 11.0.2+9-LTS
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations

Benchmark results

Benchmark                         Mode  Cnt      Score     Error  Units
CompressBenchmark.testFieldEnum   avgt    5   1861,603 ± 632,653  ns/op
CompressBenchmark.testSwitchEnum  avgt    5  10149,055 ± 338,581  ns/op

Memory allocations

Each benchmark was run separately ensuring the other enum class wasn't loaded. The memory usage was analyzed with YourKit.

BooleanFieldEnum non-heap memory usage:

BooleanFieldEnum results

G1 Eden space was 13 MB.

SwitchEnum non-heap memory usage:

SwitchEnum results

G1 Eden space was 12 MB.

Conclusions

BooleanFieldEnum is roughly 5 times faster than SwitchEnum while using pretty much the same amount of memory.

The main worry I had with the switch approach is that the constant lookup table could waste more memory than all the boolean fields. It turns out this is false. Additionally, a table lookup is far more expensive than a local field access.

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class EnumsBenchmark {
// Tested separately to avoid loading the other enum
private static final BooleanFieldEnum[] fieldConstants = BooleanFieldEnum.values();
//private static final SwitchEnum[] switchConstants = SwitchEnum.values();
private static int tries = fieldConstants.length;
@Benchmark
public boolean testFieldEnum() {
boolean result = false;
for (int i = 0; i < tries; i++) {
result ^= fieldConstants[i].isSet();
}
return result;
}
/*@Benchmark
public boolean testSwitchEnum() {
boolean result = false;
for (int i = 0; i < tries; i++) {
result ^= switchConstants[i].isSet();
}
return result;
}*/
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(CompressBenchmark.class.getSimpleName())
.forks(1)
.build();
new Runner(options).run();
}
}
public enum SwitchEnum {
// 2000 enum constants
public boolean isSet() {
switch (this) {
// 1000 cases randomly selected
return true;
default:
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment