← Назад к вопросам
Как устроен по памяти массив примитивов?
1.8 Middle🔥 81 комментариев
#JVM и управление памятью
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Структура массива примитивов в памяти Java
Это глубокий вопрос о том, как JVM хранит данные. Понимание этого критично для оптимизации производительности и отладки проблем с памятью.
Базовая структура
Массив в Java — это объект с заголовком и блоком данных. Структура выглядит так:
Объект Array:
┌─────────────────────────────────────┐
│ Object Header (12-16 байт) │
│ - Mark Word (8 байт) │
│ - Klass Pointer (4 байт, или 8) │
│ - Array Length (4 байт) │
├─────────────────────────────────────┤
│ Data (примитивные значения) │
│ int[] → каждый int занимает 4 байта │
│ long[] → каждый long занимает 8 байт│
│ byte[] → каждый byte занимает 1 байт│
└─────────────────────────────────────┘
Размер заголовка объекта
Object Header состоит из:
- Mark Word (8 байт) — хеш-код, флаги блокировки, возраст объекта
- Klass Pointer (4-8 байт) — указатель на класс в Metaspace
- Array Length (4 байта) — только для массивов, хранит длину
Итого: 16 байт на 64-битной JVM (с compressed OOP)
Пример для int[]
int[] array = new int[100];
// Размер в памяти:
// Object Header: 16 байт
// Data: 100 * 4 = 400 байт
// Padding: 0 байт (уже выровнено на 8 байт)
// Всего: 416 байт
Пример для byte[]
byte[] bytes = new byte[50];
// Размер в памяти:
// Object Header: 16 байт
// Data: 50 * 1 = 50 байт
// Padding: 6 байт (выровнять на 8: 66 → 72)
// Всего: 72 байта
Выравнивание памяти (Alignment)
JVM выравнивает размер объектов на 8 байт по умолчанию (может быть 16). Это улучшает производительность кэша.
int[3]:
- Header: 16 байт
- Data: 3 * 4 = 12 байт
- Сумма: 28 байт
- Padding: 4 байта (до ближайшего кратного 8 = 32)
- Итого: 32 байта
Сравнение с массивом объектов
Очень важное отличие — массив примитивов vs массив объектов:
// Массив примитивов — данные лежат в сплошном блоке
int[] primitives = new int[1000];
// Память: линейная, кэш-friendly
// Массив объектов — ссылки лежат, сами объекты где-то в heap
Object[] objects = new Object[1000];
// Object Header (16 байт)
// 1000 * 8 байт = 8000 байт ссылок
// Сами объекты могут быть разбросаны по heap (плохо для кэша)
Оптимизация в 64-битной JVM
Compressed Ordinary Object Pointers (OOP):
-XX:+UseCompressedOops → Указатели 4 байта вместо 8
-XX:+UseCompressedClassPointers → Klass Pointer тоже 4 байта
Это уменьшает overhead и улучшает кэширование.
Кэширование и производительность
Массив примитивов лучше для производительности:
// ✅ БЫСТРО — данные в одном куске памяти
int[] array = new int[1000000];
for (int i = 0; i < array.length; i++) {
array[i]++; // CPU может prefetch следующие элементы
}
// ❌ МЕДЛЕННО — ссылки на разрозненные объекты
Integer[] array = new Integer[1000000];
for (Integer i : array) {
i++; // Каждый Integer может быть где-то далеко в памяти
}
Утечки памяти с массивами
public class Cache {
private Object[] buffer = new Object[100];
private int size = 0;
public void add(Object obj) {
buffer[size++] = obj;
}
public Object remove() {
if (size == 0) return null;
Object obj = buffer[--size];
// ❌ ПРОБЛЕМА: buffer[size] ещё указывает на объект!
// GC не может удалить объект, пока массив его "помнит"
return obj;
}
// ✅ ПРАВИЛЬНО:
public Object removeFixed() {
if (size == 0) return null;
Object obj = buffer[--size];
buffer[size] = null; // Явно удалить ссылку
return obj;
}
}
Проверка размера объекта
// Использовать JOL (Java Object Layout) для анализа
import org.openjdk.jol.info.ClassLayout;
public class ArrayMemoryTest {
public static void main(String[] args) {
int[] array = new int[10];
System.out.println(ClassLayout.parseInstance(array).toPrintable());
// Вывод покажет точную структуру в памяти
}
}
Важные выводы
- Массив примитивов — это объект с линейным блоком данных
- Заголовок занимает 16 байт на 64-bit JVM
- Каждый примитив занимает фиксированное место (int=4, long=8, byte=1 и т.д.)
- Размер выравнивается на 8 байт
- Массивы примитивов кэш-friendly и быстрее массивов объектов
- Нужно явно обнулять ссылки в больших массивах, иначе GC не удалит объекты