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

Во многих современных компьютерных системах используется динамическое выделение памяти. Система поддерживает «кучу» (heap) свободной памяти, и во время выполнения код выделяет память из неё. Для «сборки мусора», то есть возврата ресурсов в кучу, применяются сложные алгоритмы.

Всё это создаёт существенные накладные расходы и затрудняет полное прогнозирование работы системы.

Бывают ли ситуации, когда память заканчивается? При проектировании и тестировании системы «на стенде» сказать это сложно.

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

Tibbo BASIC и Tibbo C опираются на более простую и надёжную модель статического выделения памяти. Вся память для всех переменных и функций выделяется во время компиляции. Поведение системы полностью предсказуемо: если приложение компилируется, неприятных сюрпризов во время выполнения не будет!

Алгоритм выделения памяти

Выделение начинается с глобальных переменных (включая переменные из HTML-файлов), а также локальных статических переменных в C. Место под них резервируется на постоянной основе.

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

Затем TIDE строит цепочку (дерево) вызовов - «кто кого вызывает» для каждой процедуры проекта. Кроме того, TIDE вычисляет, сколько байт памяти нужно каждой процедуре.

Точек входа в этой карте столько же, сколько обработчиков событий в приложении, ведь любое выполнение кода начинается с вызова обработчика события.

Естественно, могут быть процедуры, которые входят в «пути» нескольких обработчиков событий, как boo() на диаграмме ниже.

Блок-схема «путей» обработчиков событий.

Далее TIDE назначает начальные адреса памяти для каждой процедуры.

После этого TIDE выделяет память под стек. Её объём определяется самой длинной цепочкой вызовов в проекте.

Наконец, если проект компилируется для отладки, TIDE добавляет память, необходимую для обработки команд отладки.

Блок-схема, иллюстрирующая выделение памяти при отладке.

Итак, общий объём памяти, необходимый проекту, складывается из:

  • Глобальных и статических переменных плюс памяти для передачи аргументов и возвращаемых значений
  • Памяти под стек
  • Памяти для обработки команд отладки (выделяется только при компиляции проекта для отладки)
  • Памяти для самой длинной цепочки вызовов (в этом примере - цепочки с точкой входа on_sys_init())

Есть дополнительные правила выделения памяти, которые применяются при использовании оператора doevents.

Следствия

У модели статического выделения памяти есть свои ограничения.

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

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

Исходный материал Tibbo обновлён 12 июля 2022Оригинал на docs.tibbo.com · Сообщить об ошибке