これは、JVMの実装と基盤となるハードウェアに依存します。最近のほとんどのハードウェアは、メモリから(または1次キャッシュからも)1バイトをフェッチしません。つまり、より小さいプリミティブタイプを使用しても、通常、メモリ帯域幅の消費量は減りません。同様に、最近のCPUのワードサイズは64ビットです。より少ないビットで操作を実行できますが、余分なビットを破棄することで機能します。
唯一の利点は、プリミティブ型が小さくなると、特に配列を使用する場合に、メモリレイアウトがよりコンパクトになることです。これによりメモリが節約され、参照の局所性が向上し(キャッシュミスの数が減る)、ガベージコレクションのオーバーヘッドが減少します。
ただし、一般的に言えば、小さいプリミティブタイプを使用する方が速くはありません。
これを実証するために、次のベンチマークを見てください。
package tools.bench;
import java.math.BigDecimal;
public abstract class Benchmark {
final String name;
public Benchmark(String name) {
this.name = name;
}
abstract int run(int iterations) throws Throwable;
private BigDecimal time() {
try {
int nextI = 1;
int i;
long duration;
do {
i = nextI;
long start = System.nanoTime();
run(i);
duration = System.nanoTime() - start;
nextI = (i << 1) | 1;
} while (duration < 100000000 && nextI > 0);
return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return name + "\t" + time() + " ns";
}
public static void main(String[] args) throws Exception {
Benchmark[] benchmarks = {
new Benchmark("int multiplication") {
@Override int run(int iterations) throws Throwable {
int x = 1;
for (int i = 0; i < iterations; i++) {
x *= 3;
}
return x;
}
},
new Benchmark("short multiplication") {
@Override int run(int iterations) throws Throwable {
short x = 0;
for (int i = 0; i < iterations; i++) {
x *= 3;
}
return x;
}
},
new Benchmark("byte multiplication") {
@Override int run(int iterations) throws Throwable {
byte x = 0;
for (int i = 0; i < iterations; i++) {
x *= 3;
}
return x;
}
},
new Benchmark("int[] traversal") {
@Override int run(int iterations) throws Throwable {
int[] x = new int[iterations];
for (int i = 0; i < iterations; i++) {
x[i] = i;
}
return x[x[0]];
}
},
new Benchmark("short[] traversal") {
@Override int run(int iterations) throws Throwable {
short[] x = new short[iterations];
for (int i = 0; i < iterations; i++) {
x[i] = (short) i;
}
return x[x[0]];
}
},
new Benchmark("byte[] traversal") {
@Override int run(int iterations) throws Throwable {
byte[] x = new byte[iterations];
for (int i = 0; i < iterations; i++) {
x[i] = (byte) i;
}
return x[x[0]];
}
},
};
for (Benchmark bm : benchmarks) {
System.out.println(bm);
}
}
}
私のやや古いノートに印刷されます(列を調整するためにスペースを追加します):
int multiplication 1.530 ns
short multiplication 2.105 ns
byte multiplication 2.483 ns
int[] traversal 5.347 ns
short[] traversal 4.760 ns
byte[] traversal 2.064 ns
ご覧のとおり、パフォーマンスの違いはごくわずかです。アルゴリズムの最適化は、プリミティブタイプの選択よりもはるかに重要です。