Автор оригинала: Ali Dehghani.
1. Обзор
В этой быстрой статье мы увидим, каков след булеан значение в СПМ в различных обстоятельствах.
Во-первых, мы проинспектировать JVM, чтобы увидеть размеры объекта. Тогда мы поймем обоснование этих размеров.
2. Настройка
Для проверки макета памяти объектов в JVM мы собираемся использовать макет объекта Java ( ДЖОЛ ) широко. Поэтому нам нужно добавить jol-core зависимость:
org.openjdk.jol jol-core 0.10
3. Размеры объектов
Если мы попросим JOL распечатать детали VM с точки зрения размеров объектов:
System.out.println(VM.current().details());
Когда сжатые ссылки включены (поведение по умолчанию), мы увидим выход:
# Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
В первых нескольких строках мы можем увидеть некоторую общую информацию о VM. После этого мы узнаем о размерах объектов:
- Java ссылки потребляют 4 байта, булеан s/ byte s 1 byte, char s/ короткие s 2 байта, int s/ поплавок s 4 байта, и, наконец, долго s/ двойной s 8 байтов
- Эти типы потребляют одинаковое количество памяти, даже когда мы используем их в качестве элементов массива
Таким образом, в присутствии сжатых ссылок, каждый булеан значение занимает 1 byte. Аналогичным образом, каждый булеан в булеане потребляет 1 byte. Тем не менее, выравнивание обивки и заготовки объектов может увеличить пространство, потребляемое булеан и булеане как мы увидим позже.
3.1. Нет сжатых ссылок
Даже если мы отключим сжатые ссылки через -XX:-UseCompressedOops , размер boolean не изменит на всех :
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
С другой стороны, ссылки Java берут в два раза больше памяти.
Так что, несмотря на то, что мы могли бы ожидать в первую очередь, булеаны потребляют 1 тотализатор вместо всего 1 бита.
3.2. Слово Разрыв
В большинстве архитектур нет способа получить доступ к одному биту атоманно. Даже если бы мы хотели сделать это, мы, вероятно, в конечном итоге писать на соседние биты при обновлении другого.
Одной из целей СПМ является предотвращение этого явления, известного как слово разрывая . То есть в СПМ каждая область и элемент массива должны быть отдельными; обновления одного поля или элемента не должны взаимодействовать с чтениями или обновлениями какого-либо другого поля или элемента.
Напомним, вопросы адресности и разрыва слов являются основными причинами, по которым булев s больше, чем просто один бит.
4. Обыкновенные указатели объектов (OOPs)
Теперь, когда мы знаем булеан s 1 byte, рассмотрим этот простой класс:
class BooleanWrapper { private boolean value; }
Если мы проверяем макет памяти этого класса с помощью JOL:
System.out.println(ClassLayout.parseClass(BooleanWrapper.class).toPrintable());
Затем JOL распечатает макет памяти:
OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 1 boolean BooleanWrapper.value N/A 13 3 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
BooleanWrapper макет состоит из:
- 12 байтов для заголовка, в том числе два марк слова и один Класс слово. СПМ HotSpot использует марк слово для хранения метаданных GC, хэш-кода идентификации и информации о блокировке. Кроме того, он использует Класс слово для хранения метаданных класса, таких как проверки типа времени выполнения
- 1 тотализатор для фактического булеан ценность
- 3 байта обивки для выравнивания целей
По умолчанию ссылки на объекты должны быть выровнены на 8 байтов. Таким образом, JVM добавляет 3 байта до 13 байтов заголовка и булеан чтобы сделать его 16 байтов.
Поэтому булеан поля могут потреблять больше памяти из-за их выравнивания поля.
4.1. Пользовательское выравнивание
Если мы изменим значение выравнивания до 32 через -XX:ОбъектПовинениеInBytes-32, затем один и тот же макет класса изменяется на:
OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 1 boolean BooleanWrapper.value N/A 13 19 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 0 bytes internal + 19 bytes external = 19 bytes total
Как показано выше, JVM добавляет 19 байтов обивки, чтобы сделать размер объекта кратным 32.
5. Массив OOPs
Давайте посмотрим, как JVM излагает булеан массив в памяти:
boolean[] value = new boolean[3]; System.out.println(ClassLayout.parseInstance(value).toPrintable());
Это будет печатать макет экземпляра следующим образом:
OFFSET SIZE TYPE DESCRIPTION 0 4 (object header) # mark word 4 4 (object header) # mark word 8 4 (object header) # klass word 12 4 (object header) # array length 16 3 boolean [Z.# [Z means boolean array 19 5 (loss due to the next object alignment)
В дополнение к двум марк слова и один Класс слово, массив указатели содержат дополнительные 4 байта для хранения их длины.
Так как наш массив имеет три элемента, размер элементов массива составляет 3 байта. Тем не менее, эти 3 байта будут проложены 5 байтами выравнивания поля для обеспечения надлежащего выравнивания.
Хотя каждый булеан элемент в массиве составляет всего 1 тотализатор, весь массив потребляет гораздо больше памяти. Другими словами, мы должны рассмотреть заголовок и обивка накладных расходов при вычислении размера массива.
6. Заключение
В этом быстром учебнике, мы увидели, что булеан поля потребляют 1 byte. Кроме того, мы узнали, что мы должны рассмотреть заголовок и обивка накладных расходов в размерах объектов.
Для более подробного обсуждения настоятельно рекомендуется проверить Упс раздел СПМ исходный код. Кроме того, Алексей Шипилов имеет гораздо более углубленные статьи в этой области.
Как обычно, все примеры доступны более на GitHub .