Skip to content

Оперативная память

Материал проходит ревью.

НовичокФундамент ~24 мин

Границы темы

Разбираем: зачем запущенной программе RAM, как данные получают адреса, чем DRAM отличается от накопителя и как наблюдать память процесса.

Пока не разбираем: виртуальные адреса и страницы, NUMA, точные DDR-тайминги, устройство сборщика мусора.

Перед статьёй полезно прочитать о кеше процессора.

Результаты обучения

После статьи читатель сможет:

  1. объяснить назначение RAM;
  2. сравнить регистры, кеш, RAM и SSD;
  3. проследить жизненный цикл выделенного буфера;
  4. назвать последствия нехватки памяти;
  5. измерить память простого Node.js-процесса.

Основная модель

RAM — основное рабочее хранилище запущенных программ. В ней находятся код, текущие данные и промежуточные результаты.

Диаграмма

RAM называют памятью с произвольным доступом: можно обратиться к разным адресам без последовательного просмотра всех предыдущих данных.

Основные термины

ТерминПростое определение
RAMРабочая память компьютера
DRAMРаспространённый тип RAM, требующий периодического обновления
АдресНомер места, по которому находят данные
ВыделениеПолучение области памяти для программы
ОсвобождениеВозврат памяти для повторного использования
RSSЧасть памяти процесса, находящаяся в RAM
SwapИспользование накопителя как более медленной поддержки памяти

End-to-end сценарий

Пусть сервер получает JSON со списком заказов:

  1. Сетевые байты попадают в буфер.
  2. Программа создаёт в RAM строки, числа и объекты.
  3. Код проверяет поля и считает сумму.
  4. Результат превращается в байты ответа.
  5. Временные объекты больше не нужны.
  6. Runtime сможет повторно использовать их память.
Диаграмма

Детали зависят от языка. В JavaScript освобождение объектов обычно организует сборщик мусора; в других языках память может освобождаться явно или по времени жизни значения.

Что происходит под капотом

Байты и адреса

RAM хранит биты, сгруппированные в адресуемые байты. Тип данных задаёт программа:

text
Адрес      Байты             Возможный смысл
0x1000     34 32             символы "42"
0x2000     2a 00 00 00       целое число 42 в одном из форматов

Одни байты не сообщают свой тип. Код должен знать формат, длину и порядок.

Как работает DRAM

Современная основная память часто построена на DRAM. Упрощённо один бит хранится как электрическое состояние небольшой ячейки. Заряд постепенно утекает, поэтому контроллер должен периодически обновлять данные.

Диаграмма

Реальные модули имеют банки, строки, столбцы и сложные тайминги. Для начала важно только следствие: RAM не является мгновенной и тоже имеет внутреннее устройство.

Выделение памяти

Когда программа создаёт объект, runtime ищет подходящее место в уже полученной памяти. Если места мало, он может запросить у ОС дополнительные области.

ОС выдаёт процессу адресное пространство и отображает его части на физическую память. Программа обычно работает не с физическими адресами модулей RAM. Это тема виртуальной памяти.

Освобождение памяти

Память должна стать доступной снова. Если программа продолжает хранить ссылки на ненужные объекты, runtime считает их нужными. Так появляется логическая утечка памяти: использование растёт вместе с обработанной работой.

Возврат памяти runtime не всегда сразу уменьшает показатель процесса в ОС. Runtime может оставить область для будущих объектов.

Что происходит при нехватке

ОС может:

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

Swap медленнее RAM, потому что использует накопитель. Он может помочь пережить давление памяти, но не превращает SSD в равноценную оперативную память.

Минимальный воспроизводимый пример

Node.js покажет память процесса до и после создания буфера на 64 МиБ:

js
function show(label) {
  const memory = process.memoryUsage();
  console.log(label, {
    rssMiB: Math.round(memory.rss / 1024 / 1024),
    arrayBuffersMiB: Math.round(memory.arrayBuffers / 1024 / 1024),
  });
}

show("До");
const buffer = Buffer.alloc(64 * 1024 * 1024, 1);
show("После");
console.log("Первый и последний байты:", buffer[0], buffer[buffer.length - 1]);

Сохраните код в ram-usage.mjs и запустите:

bash
node ram-usage.mjs

Ожидаемый результат

arrayBuffersMiB после выделения увеличится примерно на 64. rssMiB также обычно вырастет, но разница не обязана равняться ровно 64 МиБ: процесс уже использует память для Node.js, кода и служебных структур.

Последняя строка:

text
Первый и последний байты: 1 1

подтверждает, что буфер создан и доступен.

Как диагностировать ошибку

  • node не найден — установите Node.js или проверьте PATH;
  • числа отличаются между запусками — это нормально для процесса с runtime;
  • rssMiB изменился не ровно на 64 — RSS включает больше одного буфера;
  • процесс завершён — проверьте лимит памяти среды;
  • не увеличивайте размер до гигабайтов на машине с небольшим объёмом RAM.

Ограничения и trade-offs

РешениеВыигрышЦена
Держать данные в RAMБыстрый повторный доступОграниченная ёмкость
Читать частямиМеньше пик памятиСложнее поток обработки
Кешировать результатМеньше повторной работыНужны место и правила удаления
Использовать swapДополнительный запасНамного более медленный доступ
Добавить RAMБольше рабочего набораЦена и предел оборудования

Для backend важна не только средняя память, но и пик: много одновременных запросов могут одновременно создать большие буферы.

Failure modes и типичные ошибки

  • RAM и SSD — одно хранилище. У них разные роли и свойства.
  • Свободная память обязана всегда быть пустой. ОС использует её для полезных кешей и освобождает при необходимости.
  • Сборщик мусора исключает утечки. Доступные по ссылкам, но ненужные объекты не считаются мусором.
  • RSS равен размеру объектов языка. Он включает код, runtime и другие области.
  • Swap так же быстр, как RAM. Это более медленная аварийная поддержка.
  • Выделение гарантирует физическую RAM немедленно. ОС и runtime могут выделять и отображать память поэтапно.

Для чувствительных данных важно управлять временем жизни буферов и не использовать неинициализированную память. Например, Buffer.alloc в Node.js заполняет новый буфер, а Buffer.allocUnsafe требует осторожной полной перезаписи.

Практическое задание

Задача: запустите пример с буферами 8, 32 и 64 МиБ и запишите показатели.

Критерии готовности:

  • каждый запуск начинается новым процессом;
  • записаны rssMiB и arrayBuffersMiB;
  • первый и последний байты проверены;
  • сформулировано, почему RSS не равен только размеру буфера;
  • эксперимент не превышает безопасный объём памяти машины.
Подсказка

Меняйте только первое число в Buffer.alloc. Новый процесс нужен, чтобы предыдущий буфер и решения runtime не влияли на следующий размер.

Проверка знаний

ИНТЕРАКТИВНАЯ ПРОВЕРКА

Рабочая память программы

0 / 4
01Для чего программа в первую очередь использует RAM?
02Что может занимать RAM процесса?
03Восстановите жизненный цикл рабочего буфера.
  1. Освободить, когда буфер больше не нужен
  2. Запросить память у runtime или ОС
  3. Прочитать и изменить данные
  4. Получить доступную область
04Если в системе почти нет полностью свободной RAM, она обязательно сломана.
Проверено: 0 из 4

Самопроверка

  1. Чем RAM отличается от накопителя?
  2. Почему DRAM нужно обновлять?
  3. Что означает выделить память?
  4. Почему сборщик мусора не гарантирует отсутствие утечек?
Ответы и критерии
  1. RAM хранит текущее энергозависимое состояние; накопитель — долговременные файлы.
  2. Электрическое состояние ячеек постепенно ослабевает, поэтому данные восстанавливаются периодическим обновлением.
  3. Получить область адресного пространства для кода или данных программы.
  4. Объект с оставшейся ссылкой считается достижимым, даже если бизнес-логике он уже не нужен.

Краткое резюме

  • RAM хранит рабочее состояние запущенных программ.
  • Данные находятся по адресам и получают смысл из формата.
  • DRAM энергозависима и требует периодического обновления.
  • Runtime и ОС вместе организуют выделение памяти процессу.
  • Нехватка памяти приводит к замедлению, отказу выделения или завершению процесса.
  • Память backend-сервиса нужно измерять под реальной одновременной нагрузкой.

Следующие шаги

Следующие темы трека — Stack и Heap. Они объяснят две важные области, в которых программа организует данные во время выполнения.

Источники

  • Micron: How DRAM memory works — устройство ячейки DRAM, банки, строки, столбцы и обновление данных.
  • Micron: Intro to memory — официальное учебное сравнение DRAM и энергонезависимой NAND-памяти.
  • Node.js: process.memoryUsage() — значения rss, heapUsed, external и arrayBuffers из практического примера.
  • Linux kernel: /proc filesystem — определение RSS и других показателей памяти процесса в Linux.
  • Linux kernel: Memory Management — первичная документация по выделению, виртуальной памяти и управлению памятью ОС.