Java short, integer, long performance
Я читал, что JVM хранит внутренне короткие, целые и длинные как 4 байта. Я прочитал его из статьи с 2000 года, поэтому я не знаю, насколько это верно сейчас.
Для новых JVMs есть ли увеличение производительности при использовании short over integer/long? И изменилась ли эта часть реализации с 2000 года?
Спасибо
Ответы
Ответ 1
long 64 –9,223,372,036,854,775,808 to 9 ,223,372,036,854,775,807
int 32 –2,147,483,648 to 2,147,483,647
short 16 –32,768 to 32,767
byte 8 –128 to 127
Используйте то, что вам нужно, я бы подумал, что короткие шорты редко используются из-за небольшого диапазона, и он находится в формате big-endian.
Любое увеличение производительности будет минимальным, но, как я уже сказал, если вашему приложению требуется диапазон больше, чем короткий, с int. Длинный тип может быть слишком большим для вас; но все зависит от вашего приложения.
Вы должны использовать только короткие, если у вас есть проблема с пространством (память), в противном случае используйте int (в большинстве случаев). Если вы создаете массивы и пытаетесь это сделать, объявляя массивы типа int и short. Короткие будут использовать 1/2 пространства, а не int. Но если вы запустите тесты, основанные на скорости/производительности, вы увидите мало различий (если вы имеете дело с массивами), кроме того, единственное, что вы сохраняете, - это пространство.
Также, поскольку комментатор упоминается долго, потому что длинный бит 64 бит. Вы не сможете сохранить размер длинной в 4 байта (обратите внимание на диапазон длинного).
Ответ 2
Целочисленные типы хранятся во многих байтах, в зависимости от точного типа:
- байт на 8 бит
- short на 16 бит, подписанный
- int на 32 бита, подписан
- длиной 64 бит, подписанный
См. здесь .
Что касается производительности, это зависит от того, что вы делаете с ними.
Например, если вы присваиваете буквальное значение байту или краткому, они будут масштабироваться до int, поскольку значения по умолчанию считаются ints по умолчанию.
byte b = 10; // upscaled to int, because "10" is an int
Что вы не можете сделать:
byte b = 10;
b = b + 1; // Error, right member converted to int, cannot be reassigned to byte without a cast.
Итак, если вы планируете использовать байты или шорты для выполнения некоторых циклов, вы ничего не выиграете.
for (byte b=0; b<10; b++)
{ ... }
С другой стороны, если вы используете массивы байтов или шорт для хранения некоторых данных, вы, очевидно, выиграете от их уменьшенного размера.
byte[] bytes = new byte[1000];
int[] ints = new int[1000]; // 4X the size
Итак, мой ответ: это зависит:)
Ответ 3
Это деталь реализации, но по-прежнему верно, что по соображениям производительности большинство JVM будут использовать полное слово (или больше) для каждой переменной, так как ЦП получают доступ к памяти в словарных единицах. Если JVM сохранил переменные в блоках и позициях подслова, это будет на самом деле медленнее.
Это означает, что 32-битная JVM будет использовать 4 байта для коротких (и даже булевых), в то время как 64-битная JVM будет использовать 8 байтов. Однако для элементов массива это не так.
Ответ 4
Я согласен с user2391480, расчеты с шортами кажутся дороже. Вот пример, где на моей машине (Java7 64 бит, Intel i7-3770, Windows 7) операции с шортами примерно в 50 раз медленнее, чем целые и длинные.
public class ShortTest {
public static void main(String[] args){
calculate();
calculate();
}
public static void calculate(){
int N = 100000000;
long time1=System.currentTimeMillis();
short s=0;
for(int i = 0; i<N;i++) {
s+=1;
s-=1;
}
long time2=System.currentTimeMillis();
System.out.println("Time elapsed for shorts: "+(time2-time1));
long time3=System.currentTimeMillis();
int in=0;
for(int i = 0; i<N;i++) {
in+=1;
in-=1;
}
long time4=System.currentTimeMillis();
System.out.println("Time elapsed for ints: "+(time4-time3));
long time5=System.currentTimeMillis();
long l=0;
for(int i = 0; i<N;i++) {
l+=1;
l-=1;
}
long time6=System.currentTimeMillis();
System.out.println("Time elapsed for longs: "+(time6-time5));
System.out.println(s+in+l);
}
}
Вывод:
Time elapsed for shorts: 113
Time elapsed for ints: 2
Time elapsed for longs: 2
0
Time elapsed for shorts: 119
Time elapsed for ints: 2
Time elapsed for longs: 2
0
Примечание: указание "1" должно быть коротким (во избежание кастинга каждый раз, как это предлагает пользователь Robotnik в качестве источника задержки), похоже, не помогает, например.
short s=0;
short one = (short)1;
for(int i = 0; i<N;i++) {
s+=one;
s-=one;
}
EDIT: изменено в соответствии с запросом пользователя Hot Licks в комментарии, чтобы вызывать метод calculate() более одного раза за пределами основного метода.
Ответ 5
Там в принципе нет разницы. Нужно "немного запутать" JITC, чтобы он не признавал, что операции приращения/декремента самоотменяются и что результаты не используются. Сделайте это, и три случая выйдут примерно одинаково. (На самом деле, short
кажется немного меньшим.)
public class ShortTest {
public static void main(String[] args){
// Do the inner method 5 times to see how it changes as the JITC attempts to
// do further optimizations.
for (int i = 0; i < 5; i++) {
calculate(i);
}
}
public static void calculate(int passNum){
System.out.println("Pass " + passNum);
// Broke into two (nested) loop counters so the total number of iterations could
// be large enough to be seen on the clock. (Though this isn't as important when
// the JITC over-optimizations are prevented.)
int M = 100000;
int N = 100000;
java.util.Random r = new java.util.Random();
short x = (short) r.nextInt(1);
short y1 = (short) (x + 1);
int y2 = x + 1;
long y3 = x + 1;
long time1=System.currentTimeMillis();
short s=x;
for (int j = 0; j<M;j++) {
for(int i = 0; i<N;i++) {
s+=y1;
s-=1;
if (s > 100) {
System.out.println("Shouldn't be here");
}
}
}
long time2=System.currentTimeMillis();
System.out.println("Time elapsed for shorts: "+(time2-time1) + " (" + time1 + "," + time2 + ")");
long time3=System.currentTimeMillis();
int in=x;
for (int j = 0; j<M;j++) {
for(int i = 0; i<N;i++) {
in+=y2;
in-=1;
if (in > 100) {
System.out.println("Shouldn't be here");
}
}
}
long time4=System.currentTimeMillis();
System.out.println("Time elapsed for ints: "+(time4-time3) + " (" + time3 + "," + time4 + ")");
long time5=System.currentTimeMillis();
long l=x;
for (int j = 0; j<M;j++) {
for(int i = 0; i<N;i++) {
l+=y3;
l-=1;
if (l > 100) {
System.out.println("Shouldn't be here");
}
}
}
long time6=System.currentTimeMillis();
System.out.println("Time elapsed for longs: "+(time6-time5) + " (" + time5 + "," + time6 + ")");
System.out.println(s+in+l);
}
}
Результаты:
C:\JavaTools>java ShortTest
Pass 0
Time elapsed for shorts: 59119 (1422405830404,1422405889523)
Time elapsed for ints: 45810 (1422405889524,1422405935334)
Time elapsed for longs: 47840 (1422405935335,1422405983175)
0
Pass 1
Time elapsed for shorts: 58258 (1422405983176,1422406041434)
Time elapsed for ints: 45607 (1422406041435,1422406087042)
Time elapsed for longs: 46635 (1422406087043,1422406133678)
0
Pass 2
Time elapsed for shorts: 31822 (1422406133679,1422406165501)
Time elapsed for ints: 39663 (1422406165502,1422406205165)
Time elapsed for longs: 37232 (1422406205165,1422406242397)
0
Pass 3
Time elapsed for shorts: 30392 (1422406242398,1422406272790)
Time elapsed for ints: 37949 (1422406272791,1422406310740)
Time elapsed for longs: 37634 (1422406310741,1422406348375)
0
Pass 4
Time elapsed for shorts: 31303 (1422406348376,1422406379679)
Time elapsed for ints: 36583 (1422406379680,1422406416263)
Time elapsed for longs: 38730 (1422406416264,1422406454994)
0
C:\JavaTools>java -version
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b19)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
Ответ 6
Расчеты с коротким типом чрезвычайно дороги.
Возьмите следующий бесполезный цикл, например:
short t=0;
//int t=0;
//long t=0;
for(many many times...)
{
t+=1;
t-=1;
}
Если он короткий, он будет буквально в 1000 раз дольше, чем если бы он был int или длинным.
Проверено на 64-битных версиях JVM версии 6/7 на Linux