Почему не определен логический примитив Java?

Спецификация виртуальной машины Java говорит, что существует ограниченная поддержка логических примитивных типов.

Нет никаких инструкций виртуальной машины Java, предназначенных исключительно для операций с логическими значениями. Вместо этого выражения на языке программирования Java, которые работают с логическими значениями, компилируются для использования значений типа данных виртуальной машины Java int.

Вышесказанное подразумевает (хотя я, возможно, неверно истолковал его), что тип данных int используется при работе с логическими значениями, но это 32-разрядная конструкция памяти. Учитывая, что логическое значение представляет только 1 бит информации:

  • Почему байт или короткий тип не используется в качестве прокси для логического значения вместо int?
  • Для какой-либо конкретной JVM, какой самый надежный способ точно определить, сколько памяти используется для хранения логического типа?

7 ответов

Решение

Краткий ответ: да, логические значения обрабатываются как 32-битные объекты, но массивы логических значений используют 1 байт на элемент.

Более длинный ответ: JVM использует 32-битную ячейку стека, используемую для хранения локальных переменных, аргументов метода и значений выражений. Примитивы размером менее 1 ячейки дополняются, примитивы размером более 32 бит (длинные и двойные) занимают 2 ячейки. Этот метод минимизирует количество кодов операций, но имеет некоторые специфические побочные эффекты (например, необходимость маскировать байты).

Примитивы, хранящиеся в массивах, могут использовать менее 32 бит, и существуют разные коды операций для загрузки и хранения значений примитивов из массива. И логические, и байтовые значения используют коды операций baload и bastore, что означает, что логические массивы занимают 1 байт на элемент.

Что касается компоновки объекта в памяти, то это подпадает под правила"частной реализации", это может быть 1 бит, 1 байт или, как отметил другой автор, выровнено по 64-битной границе двойного слова. Скорее всего, он принимает базовый размер слова базового оборудования (32 или 64 бита).


Что касается минимизации объема пространства, используемого булевыми значениями: для большинства приложений это не проблема. Кадры стека (содержащие локальные переменные и аргументы метода) не очень велики, и в большой схеме дискретный логический объект в объекте также не так велик. Если у вас много объектов с большим количеством логических значений, вы можете использовать битовые поля, которые управляются через ваши методы получения и установки. Тем не менее, вы будете платить штраф в процессорном времени, который, вероятно, больше, чем штраф в памяти.

Один логический объект где-то в иерархии наследования может использовать до 8 байт! Это связано с дополнением. Более подробную информацию можно найти в разделе "Сколько памяти используется моим Java-объектом"?:

Возвращаясь к вопросу о том, сколько логическое число потребляет, да, оно потребляет, по крайней мере, один байт, но из-за правил выравнивания оно может потреблять намного больше. ИМХО более интересно знать, что логическое значение [] будет потреблять один байт на запись, а не один бит, плюс некоторые издержки из-за выравнивания и для поля размера массива. Существуют графовые алгоритмы, в которых полезны большие поля битов, и вам нужно знать, что, если вы используете логическое значение [], вам потребуется почти в 8 раз больше памяти, чем действительно необходимо (1 байт против 1 бита).

5-е издание Java в двух словах (O'Reilly) говорит, что тип логического примитива составляет 1 байт. Это может быть неправильно, основываясь на том, что показывает проверка кучи. Интересно, есть ли у большинства JVM проблемы с выделением переменных для байта?

Процессоры работают с определенной длиной типа данных. В случае 32-битных процессоров они имеют длину 32 бита и, следовательно, то, что вы называете int в Java. Все, что ниже или выше, должно быть заполнено или разделено на эту длину, прежде чем ЦП сможет его обработать. Это не займет много времени, но если вам нужно 2 такта процессора вместо 1 для основных операций, это означает удвоение затрат / времени.

Эта спецификация предназначена для 32-битных процессоров, чтобы они могли обрабатывать логические значения со своим собственным типом данных.

У вас может быть только одно: скорость или память - SUN выбрал скорость.

Булево отображение было сделано с учетом 32-битного процессора. Значение int имеет 32 бита, поэтому оно может быть обработано за одну операцию.

Вот решение Java IAQ Питера Норвига: нечасто отвечаемые вопросы для измерения размера (с некоторой неточностью):

static Runtime runtime = Runtime.getRuntime();
...
long start, end;
Object obj;
runtime.gc();
start = runtime.freememory();
obj = new Object(); // Or whatever you want to look at
end =  runtime.freememory();
System.out.println("That took " + (start-end) + " bytes.");

Boolean представляет один бит информации, но его "размер" не является чем-то точно определенным, скажем, в руководствах по Sun Java. Булевы литералы имеют только два возможных значения: true и false. См. Типы данных Java для деталей.

Мы не можем сказать точный размер логического типа данных. Это зависит от виртуальной машины или варьируется от одной операционной системы к другой.

Почему бы не сделать один файл.java следующим образом:

Empty.java

class Empty{
}

и один класс, как это:

NotEmpty.java

class NotEmpty{
   boolean b;
}

Скомпилируйте их оба и сравните файлы.class с помощью шестнадцатеричного редактора.

Другие вопросы по тегам