Lohnt es sich unter gewissen Umständen oder aus Performancegründen auf kleinere primitive Datentypen statt int zu setzen? Zum Beispiel short oder byte? Dieses versuche ich im folgenden Artikel zu klären.

Benchmark von primitiven Datentypen

Um diese Frage zu beantworten, habe ich Benchmarks in zwei Bereichen auf Basis von JMH entwickelt: Während der erste Test eine Multiplikation mit Hilfe des jeweiligen primitiven Datentypen durchführt, erstellt der zweite Benchmark ein Array des jeweiligen Datentypen und füllt es mit entsprechenden Werten. Der Quellcode dazu sieht wie folgt aus:

private static final int N = 2_000_000;

@Benchmark
public int intMul() {
    int a = 1;
    for (int i = 0; i < N; i++) {
        a *= 3;
    }
    return a;
}

@Benchmark
public byte byteMul() {
    byte a = 1;
    for (int i = 0; i < N; i++) {
        a *= 3;
    }
    return a;
}

@Benchmark
public short shortMul() {
    short a = 1;
    for (int i = 0; i < N; i++) {
        a *= 3;
    }
    return a;
}

@Benchmark
public int intArray() {
    int[] x = new int[N];
    for (int i = 0; i < N; i++) {
        x[i] = i;
    }
    return x[x[3]];
}

@Benchmark
public byte byteArray() {
    byte[] x = new byte[N];
    for (int i = 0; i < N; i++) {
        x[i] = (byte) i;
    }
    return x[x[3]];
}

@Benchmark
public short shortArray() {
    short[] x = new short[N];
    for (int i = 0; i < N; i++) {
        x[i] = (short) i;
    }
    return x[x[3]];
}

Folgende relevante Soft- und Hardware kommt dabei zum Einsatz:

  • Intel(R) Xeon(R) CPU E3-1230 v3 @ 3.30GHz (Acht Kerne)
  • Linux 3.17.2-1-ARCH #1 SMP PREEMPT Wed Oct 30 20:49:39 CEST 2014 x86_64 GNU/Linux
  • Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode) java version "1.8.0_25"

Das Ausführen der Benchmarks in fünf Warmup- und fünf Messphasen in einer geforkten JVM führt zu folgenden Resultaten:

2.000.000 Einträge:

Benchmark                            Mode  Samples  Score   Error  Units
d.w.PrimitiveBenchmark.intMul        avgt        5  1,139 ± 0,033  ms/op
d.w.PrimitiveBenchmark.byteMul       avgt        5  1,675 ± 0,102  ms/op
d.w.PrimitiveBenchmark.shortMul      avgt        5  1,676 ± 0,043  ms/op

d.w.PrimitiveBenchmark.byteArray     avgt        5  1,080 ± 0,056  ms/op
d.w.PrimitiveBenchmark.shortArray    avgt        5  1,418 ± 0,046  ms/op
d.w.PrimitiveBenchmark.intArray      avgt        5  2,134 ± 0,133  ms/op

Übersetzt heißt das: Bei arithmetischen Operationen sollte man aus Performancegründen stets auf int setzen. Intern arbeitet die JVM mit 32-Bit Anweisungen, was zu zusätzlichen Operationen durch die Konvertierung in die kleineren Datentypen byte (8 Bit) und short (16 Bit) führt und somit zu einem Performanceverlust gegenüber int (32 Bit). Im Übrigen gibt es auf einem 64-Bit System keinen zeitlichen Unterschied zwischen int und long (64 Bit).

In Bezug auf den Speicherverbrauch kann der Wechsel auf den jeweils kleineren Datentyp sinnvoll sein und durchaus zu einer gesteigerten Performance führen. Hier lautet jedoch die Devise: Je kleiner die Datenmenge, desto marginaler der Unterschied. Erst bei relativ großen Datenmengen kann man über einen möglichen Wechsel des Datentyps nachdenken:

100.000 Einträge:

Benchmark                            Mode  Samples  Score   Error  Units
d.w.PrimitiveBenchmark.byteArray     avgt        5  0.055 ± 0.003  ms/op
d.w.PrimitiveBenchmark.shortArray    avgt        5  0.068 ± 0.003  ms/op
d.w.PrimitiveBenchmark.intArray      avgt        5  0.100 ± 0.006  ms/op

4.000.000 Einträge:

Benchmark                            Mode  Samples  Score   Error  Units
d.w.PrimitiveBenchmark.byteArray     avgt        5  2,107 ± 0,159  ms/op
d.w.PrimitiveBenchmark.shortArray    avgt        5  2,778 ± 0,167  ms/op
d.w.PrimitiveBenchmark.intArray      avgt        5  4,610 ± 0,148  ms/op

GitHub

Wie immer, ist der vollständige Quellcode in meinem GitHub-Repository zu finden.

blogroll
tags