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

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

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

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

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

Ответ 1

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

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

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

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


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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

Здесь решение от Peter Norvig 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.");

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

Empty.java

class Empty{
}

и один класс:

NotEmpty.java

class NotEmpty{
   boolean b;
}

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