Аллокаторы: явное управление памятью
Для трёх тарелок хватает полки. Для числа гостей, которое станет известно позже, понадобится место по запросу. Кто-то должен выдать его, сообщить об отказе и принять обратно. В программе эту работу выполняет аллокатор.
Скопируем строку в независимый блок. Это первый пример, где результат должен жить после выхода из функции, а размер определяется входом.
Одна мысль урока
Аллокатор выдаёт и принимает память, а функции явно договариваются, кто её освободит.
Опора из прошлого урока: Функции и параметры.
От картинки к записи
Аллокатор
имеет тип std.mem.Allocator. Это не сам большой массив байтов, а способ попросить конкретный
источник выдать блок. Разные источники могут использовать системную память, заранее приготовленный
буфер или общую арену.
alloc(T, count) выделяет место для count элементов T. Для u8 элемент это байт. Результат представлен срезом, поэтому у него есть длина и адрес. Выделенные байты нельзя читать, пока ты не записал в них значения: получение памяти не означает получение осмысленного текста.
В примере duplicate сразу заполняет весь блок через @memcpy. Источник и приёмник имеют одинаковую длину, поэтому копируется каждый байт. Функция возвращает ![]u8: возможна ошибка нехватки памяти либо успешный изменяемый срез. Она не прячет аллокатор в глобальной настройке, а принимает его первым параметром.
Кто освобождает результат? После успешного возврата вызывающий. Поэтому тест немедленно ставит defer allocator.free(copy). Если последующая проверка завершится ошибкой, уборка всё равно выполнится. Это полезный шаблон: получение ресурса и установка очистки стоят рядом, между ними нет другого ошибочного шага.
Освобождать нужно тем аллокатором, который выдал блок, и в соответствии с его договором. Нельзя получить память у одного источника, а вернуть другому только потому, что тип интерфейса одинаков. После free старый срез не становится null автоматически. Его байты больше нельзя использовать, даже если при эксперименте они ещё выглядят прежними.
Утечка
часто появляется при раннем возврате до очистки. Обратная ошибка, повторное освобождение, возникает, когда два уровня считают себя владельцами одного блока. Третья ошибка, использование после освобождения, возникает, когда старое окно пережило своего владельца. Все три нужно различать: один общий лозунг про «память» не показывает место исправления.
std.testing.allocator полезен в тестах: он обнаруживает неосвобождённые выделения. Это не подходящий способ получить глобальный аллокатор для любой программы. Тест предоставляет удобный контролируемый источник; приложение выбирает свой в точке запуска. Мы изучим варианты в следующем уроке.
Не выделяй память, если задача решается окном на существующие данные и срок жизни подходит. Независимая копия нужна, например, если исходный буфер будет перезаписан. Если функция только суммирует числа, новый блок ей не нужен. Явный аллокатор помогает заметить такую ненужную работу.
премиум-урок
Продолжение в премиуме: 1 200 ₽ в месяц или 10 000 ₽ в год. Вместе с ним серверные проверки задач и школьные токены AI-коуча.
Оплата пока не подключена: премиум и курсы открываются промокодом.