Давным-давно, когда с ездовым котом приключилась "записка шестая", а знания об аллокаторах и опыт их применения ограничивался линейным и системным, перебросили мою команду в помощь другой команде, которая занималась системами навигации больших судов. Ездовые коты, особенно нестарые - это такие создания, которые редко изучают документацию детально, а чаще бегло читают там про интерфейсы систем в проекте, malloc, new, системные аллокаторы и думают, что теперь-то точно понятно, как всё устроено. А потом приходит работа и такая: “Забудь всё, что ты знал. Ты не дочитал до страницы восемьсот что-то там РД, тут есть свой аллокатор - и он реально плохой”.

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

А вот почему нужны и важны ненормальные - объяснений почти нет, как и самих реализаций в открытом доступе. В этой статье я расскажу, какие повстречал ненормальные алгоритмы распределения памяти, чем они живут, кого едят, и почему иногда malloc делает вид, что он не при делах и таки да, malloc может возвращать null и ту проверку мы убрали зря.


Чтобы понять, как устроен аллокатор, можно представить его как небольшую систему управления памятью внутри программы. Он отвечает за то, чтобы выделять, отдавать, освобождать и при необходимости полностью уничтожать области памяти. Обычно можно выделить пять базовых операций, с помощью которых описывается работа любого аллокатора (хотя не каждый аллокатор обязательно поддерживает их все в явном виде).

create/создание аллокатора

Инициализирует аллокатор, ему выделяется определённый участок памяти и это может быть, например, заранее зарезервированный буфер фиксированного размера или блок, полученный из системного аллокатора (например, через malloc или VirtualAlloc).
По сути, аллокатор начинает «жить» внутри этого участка и управлять им самостоятельно, раздавая память по запросу программы. Главная идея в том, что после вызова create аллокатор больше не обращается напрямую к операционной системе. Он работает внутри выделенного ему пространства, что делает выделения памяти быстрее и предсказуемее.

allocate/выделение блока

Используется для запроса памяти из управляемой области, программа сообщает, сколько байт ей нужно, а аллокатор ищет подходящий участок внутри своего пространства и возвращает указатель. В зависимости от типа аллокатора это может быть просто линейное смещение или более сложный поиск подходящего блока. Ключевая особенность — скорость (за этот параметр борются все разработчики) и allocate часто работает за O(1), потому что аллокатор знает, как устроена его память, и не нуждается в сложных алгоритмах системных менеджеров памяти.

deallocate/освобождение блока

Делает обратное - освобождает конкретный блок, что тоже не бесплатно, ранее выделенный через allocate. В простых аллокаторах (линейных) эта операция может быть вообще не предусмотрена, и тогда память очищается вся разом в при наступлении некоторого события. Освобождение блока не всегда означает физическое стирание данных иногда просто обновляются внутренние таблицы или флаги.

free/сброс всех выделений

Очищаем все выделенные блоки, но не уничтожаем сам аллокатор и не возвращаем память системе. Фактически это «массовый сброс», после которого снова можно обслуживать новые запросы, начиная с начала своего буфера.

destroy/уничтожение аллокатора

Завершает жизнь аллокатора, освобождает участок памяти, который был выделен ему при создании, и удаляет его внутренние структуры. После вызова destroy пользоваться аллокатором уже нельзя, а все указатели, выданные им, становятся недействительными.

Все описанное выше справедливо для всех типов и видов аллокаторов, но вот конкретные цели "ненормальных" аллокаторов часто находятся очень далеко от понимания разработчика, который с ними сталкивается впервые.

Хороший...

Тут скорее уместно сказать, оптимизирующий, но тогда бы не получилось красивого заголовка. При разработке рабочего места вахтенного штурмана, который организует работу навигационной службы и контролирует работу штурманов один из крупных заказчиков потребовал использовать свою версию GCC (clang тогда ходил пешком под стол) с возможностью выгрузки статистики по памяти, т.е. буквально сколько и какие объекты были созданы, где располагались, когда уничтожались и т.д. В процессе портирования софта на этот форк, а там были не только эти требования, но и еще часть приколов и расширений, вроде невозможности выделить за раз более 1Мб памяти, появился кастомный аллокатор с отслеживанием времени жизни объектов.

Он распределял объекты по страницам памяти на основе их прогнозируемого времени жизни, которое было собрано на предыдущих запусках в виде некоторого конфига. Например, объекты, существующие всего несколько кадров, помещались в один пул, а долгоживущие — в другой. По ТЗ это "в теории" должно было уменьшать фрагментацию, и давать возможность объекты с похожими сроками существования освобождать пакетно (странично), т.е. при наступлении некоторого события страницы с короткоживущими объектами предполагалось очищать целиком (не взлетело в реальности).

Но интеграция с инструментами статистики после запусков позволила автоматически (через конфиг) "обучать" аллокатор предсказывать время жизни на основе реальных данных выполнения, снижая необходимость ручной настройки.

В действительности такой подход показал неплохие результаты при использовании в базе данных АРМ штурмана, т.е. памяти оно стало есть действительно меньше, но не в плане ускорения работы. Зато появился отдельный форк аллокатора, который помогал при профилировании утечек, так как каждая страница памяти связана с конкретной категорией времени жизни. В итоге система как аллокатор показала себя посредственно, но дала старт специализированному софту, которое позволяло отслеживать утечки памяти в рантайме без значительного снижения производительности. Позже часть наработок этой системы была портирована (уже другой командой) в общий репозиторий сlang'a и позволила сделать сам санитайзер немного быстрее.

Условно использование ASan’a приводит к двух- и трех-кратному замедлению работы, а "хороший" замедлял программу не более чем на 10%. Каждая страница памяти получала метаданные с привязкой к категории времени жизни и обеспечивала детальную трассировку утечек, позволяя идентифицировать проблемные области кода с точностью до конкретных функций и модулей. Но необходимость предварительной ручной настройки, сложность внедрения и переделки большой части кода приложений так и оставили эту разработку в стенах одной компании.

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

АЛЛОКАТОР С ОТСЛЕЖИВАНИЕМ ВРЕМЕНИ ЖИЗНИ
═══════════════════════════════════════════════════════════════════
                    ┌─────────────────────┐
                    │  НОВЫЙ ОБЪЕКТ       │
                    │  запрос памяти      │
                    └──────────┬──────────┘
                               ▼
                    ┌─────────────────────┐
                    │  АНАЛИЗ/ПРЕДСКАЗАНИЕ│
                    │  времени жизни      │
                    |эвристика+статистика │
                    └──────────┬──────────┘
                ┌──────────────┼──────────────┐
                ▼              ▼              ▼
   ╔═══════════════╗  ╔═══════════════╗  ╔═══════════════╗
   ║  СТРАНИЦА A   ║  ║  СТРАНИЦА B   ║  ║  СТРАНИЦА C   ║
   ║ Короткоживущие║  ║ Средний срок  ║  ║ Долгоживущие  ║
   ║  (1-3 кадра)  ║  ║ (минуты/часы) ║  ║(дни/недели)   ║
   ╠═══════════════╣  ╠═══════════════╣  ╠═══════════════╣
   ║ [obj][obj][ ] ║  ║ [obj][ ][obj] ║  ║ [obj][obj]    ║
   ║ [obj][ ][ ]   ║  ║ [ ][obj][ ]   ║  ║ [obj]         ║
   ║ [ ][ ][obj]   ║  ║ [obj][obj]    ║  ║ [ ][obj]      ║
   ╠───────────────╣  ╠───────────────╣  ╠───────────────╣
   ║ META: TTL=3   ║  ║ META: TTL=600 ║  ║ META: TTL=∞   ║
   ║ Категория: 1  ║  ║ Категория: 2  ║  ║ Категория: 3  ║
   ║ Trace: func_A ║  ║ Trace: func_B ║  ║ Trace: func_C ║
   ╚═══════════════╝  ╚═══════════════╝  ╚═══════════════╝
         ▼                   ▼                   ▼
    ┌─────────┐         ┌─────────┐         ┌─────────┐
    │ ОЧИСТКА │         │ ОЧИСТКА │         │ ОЧИСТКА │
    │ целиком │         │ частями │         │ редко   │
    │ каждый  │         │ по мере │         │ по      │
    │ кадр    │         │истечения│         │ запросу │
    └─────────┘         └─────────┘         └─────────┘

ОТСЛЕЖИВАНИЕ УТЕЧЕК:
════════════════════
Time N:    [A: ████░░] [B: ███░░░] [C: ████░░]  ← состояние
Time N+10: [A: ████░░] [B: ████░░] [C: ████░░]  ← норма
Time N+50: [A: ████░░] [B: █████░] [C: █████░]  ← растет
Time N+99: [A: ████░░] [B: ██████] [C: ██████]  УТЕЧКА
                            ▲           ▲
                    ┌───────┴───────────┴────────┐
                    │ ДЕТАЛЬНАЯ ТРАССИРОВКА B:   │
                    │ • Функция: path_trace()    │
                    │ • Модуль: ppath.cpp:342    │   
                    │ • Ожидалось: 600 сек       │
                    │ • Фактически: ∞            │
                    └────────────────────────────┘

Плохой...

Во время тестирования сложных и долго работающих систем, как из примера софта в предыдущей части, возникает необходимость "доказательства" стабильности системы на долгих сроках использования, что вообще-то практически нереализуемо на этапе разработки - ну какое долгосрочное тестирование, если апдейты прилетают каждый день. Добавьте сюда трудности с выявлением ошибок управления памятью, когда они проявляются крайне редко — иногда лишь спустя дни или недели непрерывной реальной работы. У компании было несколько полнофункциональных рабочих стендов максимально приближенных к условиям и данным судна, где софт, что называется "жил" по реальным записям с судов, но их было всего три, и очередь на то, чтобы туда пропихнуть тестирование своего модуля была на месяц вперед.

Чтобы как-то ускорить обнаружение такого рода ошибок, был разработан отдельный вид аллокатора — рандомизирующий (chaos), представляющий собой специализированную систему управления памятью, созданную для поиска ошибок, связанных с длительным использованием программ.

В отличие от "хороших" аллокаторов, где разработчик стремится к стабильности размещения объектов для оптимизации кеша и предсказуемости выборки данных, этот аллокатор действует прямо противоположным образом — намеренно нарушает стабильность адресного пространства. При каждой новой аллокации система может случайным образом перемещать уже существующие объекты в произвольные области памяти, создавая условия, близкие к непредсказуемым. Ну не при каждой, конечно - это самый жесткий случай, но при наступлении некоторого события и таймера. Что конечно помогает относительно быстро выявлять участки кода (относительно обычной разработки), которые полагаются на неизменность адресов — один из типичных источников трудноуловимых ошибок.

Чтобы подобное перемещение не приводило к нарушению работы программы, аллокатор использует внутреннюю таблицу трансляции адресов, разновидность дескрипторов. Она сопоставляет «логические» адреса, с которыми работает приложение, и реальные физические адреса в памяти. Благодаря этому объекты могут свободно перемещаться, а корректно написанный код продолжает функционировать, не замечая изменений. Программа как обычно «думает», что данные находятся на прежнем месте, хотя на самом деле они уже были перемещены в другую часть памяти.

Применение такого подхода позволяло выявлять ряд ошибок на ранних стадиях, которые в обычных условиях проявились бы только после длительной работы. В одном случае приложение, полагавшееся на стабильность адресов, стало аварийно завершаться уже через несколько часов после включения агрессивной рандомизации адресов, хотя без неё аналогичные сбои происходили лишь спустя недели и скорее всего уже на оборудовании заказчика, т.е. где-то в море, а вытащить дампы оттуда практически нереально и это грозило серьезным окриком со стороны начальства и некоторыми финансовыми проблемами. Для избежания разного рода проблем на судне всегда крутится 2, а то и больше резервных инстансов каждого АРМ, работающих параллельно, чтобы в случае чего просто переключиться на живой, если вдруг один отвалился, это конечно было, но очень-очень редко.

В другом случае, в модуле навигации, работающем с многопоточными запросами к базе данных, удалось обнаружить гонки по данным. Один поток кэшировал адрес структуры, а другой инициировал её перемещение, что приводило к повреждению данных и ошибке позиционирования судна. При анализе и длительном разборе пришли к выводу, что подобная ситуация не могла бы случиться на реальном железе и скорее всего это был эффект самого подхода в аллокаторе, но прецедент был и такой код починили. Повторюсь, что в реальных условиях эта ошибка могла случиться одна на пару миллиардов обращений к БД, что в среднем превышало в три раза это количество за один рейс, но ценой такой ошибки было бы смещение точки судна на несколько десятков метров от его реальной позиции.

Такой аллокатор можно рассматривать как стресс-тестер для подсистем памяти, который моделирует непредсказуемое поведение среды и помогает выявлять ошибки, зависящие от времени и порядка выполнения операций, позволяя заранее проверить устойчивость архитектуры к фрагментации, случайным сбоям и некорректным обращениям. Надо сказать, что после запуска тестов на таком аллокаторе очень много нашего тогдашнего софта "посыпалось", что привело к раздаче большого числа тасок разным подразделениям и в целом к пересмотру подхода работы с памятью.

Цветной...

Немного расскажу об очень специализированном аллокаторе, которые вы скорее всего не встретите в обычной жизни и никогда не будете использовать. Обычно - это либо внутренняя разработка-исследование студии, направленная на поиск ошибок, дебажные сборки и внутренние тулы. Их еще иногда показывают на GDC в секции - “а смотрите какую штуку мы нафигачили". Такие вещи направлены уже не на производительность, а решают свои узкоспециальные задачи.

“Цветной” аллокатор вводит концепцию "цветов памяти", чтобы жёстко разграничить данные разных подсистем. Каждое выделение сопровождается тегом цвета (RED, BLUE, GREEN и т.д.), и поддерживает внутреннюю таблицу сопоставлений страниц памяти цветам. Операции между разными цветами запрещены на уровне отладочного режима и аллокатором предоставляются собственные функции memset, memcpy и др - попытка копирования, перемещения или работы с памятью другого цвета из “цветного компонента” вызывает предупреждение или запись в лог, либо сообщение об ошибке, что помогает находить случаи ошибочного смешивания данных между системами.

В боевом режиме проверка отключена для лучшей производительности, но в отладочном режиме аллокатор способен отслеживать цвет каждой страницы памяти, предотвращая обращения к памяти "не своего" цвета. Дополнительно иногда делают механизм "цветовых барьеров", когда один цвет может читать другой, но не модифицировать его (полезно для реализации immutable-паттернов или защиты данных потоков).

ColorAllocator alloc;

auto red_data  = alloc.allocate<RED>(256);
auto blue_data = alloc.allocate<BLUE>(256);

// Безопасно: работа внутри одного цвета
alloc::memset(red_data, 0, 256);

// Ошибка: попытка скопировать память между цветами
alloc::memcpy(blue_data, red_data, 256); // assert: page color mismatch!

Мне довелось работать в качестве консультанта с командой Arkane над AI логикой персонажей в Deathloop и одной из проблем разработки стала сложность взаимодействия между тасками и потоками, какие-то таски помещались в общую очередь, другие становились потоками на время. Логика игрового мира, система рендера и физика постоянно обращались к общим данным, что приводило к крайне сложным для отладки багам и гонкам данных, которые очень негативно влияли на поведение игровых болванчиков, которые и так то "умом не блистали", а тут еще и периодически откровенно тупили при взаимодействиях с игроком и миром.

Не для нужд АI, а в целом для дебага, в движке решили внедрить экспериментальный механизм аллокации памяти на основе цветов, каждому потоку был присвоен свой цвет. Условно красный поток отвечал за игровую логику, синий — за рендер, зелёный — за физику, оттенки задач получались из цвета того потока, который их создавал. Попытка записать данные одного цвета из другого потока вызывала ошибку, и выявила просто громадное число проблем синхронизации. Такой цветной аллокатор был сделан на основе TLSF.

Отловили кучу разных проблем, скрытой порчи памяти и разных несоответствий. Помимо потоков, чуть позже этот механизм применили для изоляции подсистем и там уже нашли «протечки» данных между рендером и остальным игровым кодом. Нашли на тестах, что подсистема анимации "случайно" модифицировала данные физики, и это приводило к странным «дергам и телепортам» персонажей, починили.

Или другой пример использования был сделан для неизменяемых (immutable) данных. Это мы так думали что они неизменяемые, а игре было на это просто пофиг. Ресурсы, которые были помечены как «read-only» (PURPLE) не разрешалось менять после старта уровня, там тоже нашли немало багов, чем сильно упростили жизнь QA отдела перед релизом.

 ┌───────────────┐     ┌──────────────────┐     ┌──────────────────┐
 │     RED       │     │      BLUE        │     │      GREEN       │
 │ (Game Logic)  │     │   (Rendering)    │     │    (Physics)     │
 │---------------│     │------------------│     │------------------│
 │ Object A      │     │ Vertex Buffer    │     │ Collision Map    │
 │ Object B      │     │ Texture Data     │     │ Rigid Bodies     │
 └───────┬───────┘     └────────┬─────────┘     └────────┬─────────┘
         │ копирование          │  копирование           │
         │ запрещено            V   разрешено            │
         ^----------------------V      ^-----------------V

... и быстрый (TLSF)

В разработке софта нет единого стандарта или алгоритма распределения памяти, который был бы одинаково эффективен для всех случаев использования. Игровые движки сильно отличаются от обычных приложений по шаблонам использования памяти: требуют предсказуемой производительности, тут они ближе к РТОС, минимальных задержек при аллокации - тут мы заимствуем часть от встроенных систем и строгого контроля фрагментации памяти, это уже чисто игродевовская хотелка.

Лучше всего по этим трех параметрам подходит алгоритм двухуровневых списков с разделением по размерам, реализацию можно найти тут (https://github.com/mattconte/tlsf) , который обеспечивает постоянное время выполнения операций аллокации, освобождения памяти и низкий уровень фрагментации.

Аллокатор использует стратегию "подходящих блоков" (good fit), выделяя минимальный объем памяти, достаточный для размещения запрашиваемых данных. Это больше всего подходит к шаблону использования памяти игровыми движками - аллокации происходят в относительно узких диапазонах размеров: игровые объекты, компоненты систем, временные буферы. Этот метод также минимизирует фрагментацию памяти по сравнению с альтернативными стратегиями, такими как "первый подходящий блок" (first fit), поскольку фрагментация в этих случаях может привести к невозможности выделения памяти для больших ресурсов (модели, AI или звуковые файлы) даже при наличии достаточного общего объема свободной памяти. “Лучший среди доступных” (best fit) лучше подходит для минимизации фрагментации, но проигрывает по скорости работы - поэтому эту стратегию выбирают реже (иллюстрация @Serpentine)

TLSF не очищает и не проверяет права доступа выделяемой памяти, как делают некоторые аллокаторы, что повышает общую производительность. Это оправдано, поскольку игровые движки работают в контролируемой среде, где программисты не рассматриваются как потенциальная угроза безопасности. Инициализация памяти требует дополнительных вычислительных ресурсов, которые лучше использовать для игровой логики, рендеринга и обработки игровых систем и ответственность за корректную инициализацию данных лежит на самом разработчике. Зато он очень быстрый, ниже в таблице показано количество циклов процессора (*), которое требуется для одной аллокации разными реализациями.

Size
(bytes)

malloc (std, win)
(First-Fit)*

malloc (std, win)
(Best-Fit)*

DL’s malloc*
(win)

Binary Вuddy*
(win)

TLSF*

128

25636

112566

7376

4140

155

243

22124

91216

5660

4448

168

512

15974

82162

5445

4248

159

4097

14743

65661

3346

4135

162

... заключение

Знаете, что я заметил за время работы над играми? Куча памяти, которую мы выделяем, живет всего один кадр. Серьезно, всего один кадр! Рождается, живет свои 16 - 33 миллисекунды и умирает, но даже в этом случае универсального ответа на вопрос "какой аллокатор лучше" не существует - все зависит только конкретной задачи.

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

Немного рекламы моего курса по программированию на Stepik

Примерно с полгода назад, я опубликовал на Хабре цикл статей про игровую разработку (начинать можно отсюда https://habr.com/ru/articles/873016/), которая была хорошо принята сообществом. Мои знакомые и некоторые Хабровчане просили выложить эту информацию в более удобном и концентрированном виде, в виде курса по С++ или одной большой статьи. Решил сделать пробный шар в виде небольшого курса по программированию на С++ без аллокаций, он действительно небольшой - всего 45 уроков и захватил пару статей из цикла, но если вам понравится можно попробовать сделать еще один по интересным темам (Нескучное программирование. С++ без аллокаций памяти). Курс платный, дабы отсеять охотников на халявные сертификаты и любителей пошуметь в коментах. Тем кто меня читает - промокод (HABR50), если нужна скидка больше или бесплатный инвайт напишите в личку.

Ссылки на интересные материалы и статьи

Комментарии (15)


  1. Jijiki
    10.10.2025 07:04

    очень поверхностно


    1. dalerank Автор
      10.10.2025 07:04

      Это открытая площадка и у Вас всегда есть возможность написать детальный разбор. Я здесь и не ставил целью приводить схемы и графики. В минусах есть соответствующий пункт


      1. Jijiki
        10.10.2025 07:04

        когда идёт обсуждение конструкций на основе слов - теории, тоесть повествует разработчик, и разработчик даёт маленькие примеры, а все доводы сводятся, высотой то получается возможно у вас приоритеты просто другие, но на деле есть ОС(разные ос бывают, разный диспетчер и набор возможностей) - компилятор(разные компиляторы по разному что-то там делают в итоге) - окружение - настроеный проект - пример/примеры, иначе для кого вы повествуете и показываете маленькие примеры? всё разрозрено получается, нету пруфа - конечного примера с примерами. Да понятно, что вы хотите так рассказывать, но вы же говорите про сложные системы, а не про Hello World, и метод пересказал тут к сожалению не работает, тут побольше показывать надо

        например если говорить о текстовом редакторе на словах он сводится к созданию текстового буфера только и всего, к сожалению просто произнести если мы хотим еффективно потратить время, не достаточно, и приходится показывать пример, и там уже можно какие-то концепции показать, когда мы задаёмся такими вопросами, и есть пример, и в нём углубленное что-то это может углубить приблизить к пониманию, в тот же момент просто проговорив теорию, это никак никуда не углубляет, ну типо ну да и что такой еффект, в этом и прикол, когда человек подкрепляется такими микро запросами он может сформулировать то с чем он столкнулся на примерах, а тут маленькие примеры кругом, и они далеки от всё еще примеров, но более комплексных


        1. dalerank Автор
          10.10.2025 07:04

          А всё общение - это конструкции на основе слов, другого пока не придумали. Не всем интересно, а иногда и скучно, читать углубленные технические детали и код (которого полно на работе, а на Хабр приходят чтобы отдохнуть, а не работать), тем более что часто приводимые технические решения нельзя применить без серьезных доработок, даже если выложены полные исходники. Да и читать плюсовые исходники и разбираться, что там автор понаписал - то еще удовольствие и задача скорее техревью, а не таких текстов. Но не зная определенных подходов или опробованных решений вы будете вынуждены повторять все те ошибки, которые уже были совершены до вас, вместо того чтобы поискать решение на гитхабе или других ресурсах, возможно пейперах или статьях. Ну выложу тут исходники хаос аллокатора - серьезно думаете кто-то будет их смотреть и применять, я сам его использовал последний раз 15 лет назад на паре проектов и больше не хочу.


          1. Jijiki
            10.10.2025 07:04

            понял вас, нет решенное не интересно, интересно когда можно почитать - попробовать, вот найдите новичка(разраба) в геймдеве совсем зеленого, расскажите ему в стиле вашей статьи что-нибудь, и вот если если он будет чуть смелее он будет вам задавать вопросы те какие у людей в ВУЗах аля зачем это всё нужно, и там вопросы могут не задать, а вот если вам человек задаст эти все вопросы и что и почему - это даже лучше будет, как я понял вы опытный человек просто и у вас приоритет на ингридиентах, когда у новичков вопросы в целом, ну да можно отправить на курсы, и на книжки, но вопросы будут без ответов всё равно, так и выходит кто-то показывает на примерах в интернете и понимает этот нюанс, а кто-то рисует слайды и картинка только на слайдах

            тоесть кем вы себя позиционируете (я с вами давайте погружаться) или вот смотрите слайды и есть курсы

            эти 2 способа повествования разные, нельзя точно сказать что лучше или хуже, но смотреть как человек новичек рассказывает о своём пути как он сделал клон майнкрафта интересно, чем как аллоцировать инстансы, и картинки там дальше не предпологается там или слайд или сухой отчет

            вот есть какие-то видео уроки прям я видел по свету, так там одна наука и слайды и редкие картиночки, или оглдев, который в своём стиле, но пытается придерживаться обзора ситуации, потомучто это многоуровневая ситуация

            частично 3д и игры похожи на скульптуры, так если скульптор не лепит с учениками, как можно понять что мы лепим(только дедуктивно, но плоскость скульптинга не в дедукции ), ну словами можно сказать например лепим кубик и всё дальше все лепят как услышали


    1. AskePit
      10.10.2025 07:04

      прямо-таки очень?


      1. drWhy
        10.10.2025 07:04

        Можно ведь и подповерхностно устроить.
        У автора же найдётся историй с погружением?
        Если не с дифферентом на нос, то уж о подповерхностном рассеянии - наверняка.


    1. Serpentine
      10.10.2025 07:04

      Jijiki, я вас умоляю, не поверхностно, а достаточно для такого рода статьи.

      Например, по приведенной в статье ссылке на репозиторий с TLSF содержится ~1K loc на сях. Сферическая публикация с его описанием — это простыня не менее чем 30+ страниц A4, забитых формулами и ссылками на Кнута + пара десятков строчек сишного псевдокода. И все это добро не даст новичку полного понимания для самостоятельной реализации, а через месяц после прочтения — напрочь выветрится из головы.

      Тут же вопрос, надо ли это автору и читателям, когда более углубленный материал уже несколько раз написан другими людьми? Чтобы пацаны с уважением головами покивали и некоторые в закладки добавили да забыли насовсем, ибо повод и целесообразность применения может совсем не появиться?


      1. Jijiki
        10.10.2025 07:04

        это звучит так будто делать движок и 3д игру нереально без движка. Ладно я понял

        то что в книжках, это не совсем то, что нужно, там новичкам если такие есть надо буквально пару нюансов показывать, и тогда всё встаёт на свои места, а так можно ходить вокруг да около, там после этих нюансов будет видно, что изучать и прочее, а в книжках показывают просто общие моменты базовые, тоесть всё еще вводная, тоесть и приоритеты и акценты другие

        хотя наверно, мы все об одном и том же пишем, возможно, оно видно это даже на видео синк матрикса, но просмотрел я эти нюансы далеко не в его роликах

        если вам написать что для игры нужно дерево(одно и второе, возможно третье) то пока еще же не понятно как через дерево уловить принцип

        ниразу не видел обзоров кстати об этом, у синк матрикса и сиплюсплюсгая, еще проще примеры где суть теряется за длинной кода


        1. Serpentine
          10.10.2025 07:04

          это звучит так будто делать движок и 3д игру нереально без движка. 

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

          Когда вы пишите движок/игру, вам эта статья (да и вся их серия) может помочь, как вдохновение, источник идей или навигатор по нескольким специфичным аллокаторам, а за реализацией — добро пожаловать в гугл, искать нужный учебник/руководство/вайтпейпер/etc., параллельно воплощая все это в коде.


          1. Jijiki
            10.10.2025 07:04

            тогда, std::string - ура я создал строковый буфер да еще с деструктором, С об этом может только мечтать, так в учебниках нету инфы как раз по краеугольным моментам нюансам, там только общие моменты, наверно лучшая из них будет только Седжвик


  1. azTotMD
    10.10.2025 07:04

    Куча памяти, которую мы выделяем, живет всего один кадр.

    А что именно? Можно примеры, под что выделяется память каждый кадр?


    1. dalerank Автор
      10.10.2025 07:04

      String(framemem_ptr()) вас устроит? Вот пример прям из рабочего проекта.


      1. Jijiki
        10.10.2025 07:04

        а вы в заключении расплывчато это сформулировали как понимать это тоже не ясно, тоесть оптимизируем или не знаем? как бы иду по вашей логике строки нужны и аллокатор тоже, но нет определённости с выделением строк в фреймтайме, просто когда нет определённости сложно сказать как можно попробовать, чтобы снизить выделения памяти на строки

        какие строки уточните пожалуйста, квест буки или просто текст или текст в мире, какая кодировка, возможно там еще юникод код есть, еще зависит от ОС - платформы, и еще зависит от графического стека - апи, но ситуации чуть-чуть схожи, но определённости просто нету

        а вообще сий пазл заключается в следующем, тоесть надо поиграть в игру, как нарисовать текстуры без строки, тоесть по обращению к кешу символов прям напрямую, и части текста загонять выделив память под строки, эта ситуация зависит от набора Локали если это юникод и есть система локализации, но ситуация такая да, тоесть в базу данных можно прям строки гнать, а если не хочется выделять в фреймтайме обращаться напрямую к глифам и рисовать как-то наверно

        потом еще вспомните есть 2 подхода в кодинге

        1 if

        2 map

        вот можно все случаи выделения превратить в прямую обработку по обращению к кешу иначе придётся выделить строку или последовательность, соотв лучше перед игрой выделить нужные строки, а те глифы числовые или еще какие либо выделять, либо напрямую рисовать без выделения

        тоесть 2 числа это будет указание 2 чисел, которые в кеше возьмут 2хтекстуру(тоесть надо напрямую взять эти глифы) еще возможно есть ситуация передать или запаковать это в текстуру - тоесть текст превратить в текстуру и рисовать по uv их, ну как анимации в текстуру запаковывают, так же и текст можно загнать наверно в каком-нибудь гудини возможно


        1. Jijiki
          10.10.2025 07:04

          кстати можно снизить выделения на строки до минимума кустарными способами,

          1 при входе в игру создавать текстуры, сохранить имя персонажа как строка, тут же и генерируются квестбуки

          2 числа оставить можно как есть и вот тут есть механики, например компас убирает частично числа, время это обновление 1 раз в минуту, скорость тоже механика - спидометр, всякие кулдауны - бар загрузки, не числами можно отобразить, если принципиально уходим от чисел можно урон цветом рисовать

          итого выходит вся менюшка сгенерена в текстуру, большая часть текста в текстурах, там буквально нано числа остаются, потомучто без кулдаунов нет игр