C/C++ Организация памяти и выполнение программ, стек и куча
Для начала вспомним как работает вычислитель (рассмотрим весьма утрированно, не погружаясь в работу АЛУ, РОН и тд)
Внутри вычислителя есть память, в которой находится код программы (обычно это RAM / ОЗУ) внутри памяти каждый байт имеет смещение относительно начала памяти, именно это смещение и называют адресом в памяти.
Внутри памяти хранятся текущие операнды и действия над ними (разумеется в бинарном виде и виде инструкций) и они последовательно (многопоточность и параллельность пока оставим за кадром) выполняются с каждым тактом.
1 шаг – адрес 0x013FFF01 инструкция/операнд …
2 шаг – адрес 0x013FFF02 например переход + 4 адреса
3 шаг – адрес 0x013FFF07 …
Т.е. что мы имеем – внутри вычислителя есть память, в которой находится программа, но ведь программ может быть много, и нет гарантий что программа занимает ВСЮ оперативную память. Каждая следующая вызванная функция/программа обычно расположена в памяти с большим адресом, и является первой на освобождение (очищение).
Т.е. если смотреть на таблицу – то вызываются функции сверху вниз, а освобождаются снизу вверх.
Выделяем память: Запустили операционную систему->открыли браузер
Очищаем память: закрыли браузер -> завершили работу ОС
Память под программу рассчитывается на этапе КОМПИЛИРОВАНИЯ и ЛИНКОВКИ и выделяется в процессе выполнения программы.
Следовательно
- внутри оперативной памяти идет разбиение (фрагментация) на зоны для каждой программы.
- при вызове дополнительных программ или функций также выделяется место в памяти
- при выходе из функции/ программы место очищается.
- Скомпилированная программа имеет тот объем памяти, что ему задали
Данная память, рассчитанная на этапе компиляции/линковки и выделенная в ходе запуска программы называется стеком (stack).
Следует еще раз акцентировать внимание, что программы запускаются по принципу LIFO (Last In, First Out), то есть последний добавленный в стек кусок памяти будет первым в очереди на вывод из стека.
Звучит хорошо и красиво, но при работе с данными мы не всегда можем знать сколько еще памяти нам понадобится, что же делать? Ведь память на стеке уже выделена?
Для этого можно использовать остальную память – она называется куча (heap). В ходе работы программы мы можем динамически (по своему хотению, в любой момент времени, при наличии свободного места) выделять дополнительную память и работать через ее адреса.
Эта дополнительная память, выделенная в куче и с которой работают из стека называется динамической памятью.
Схематично стек и куча обозначены на рисунке, из области памяти DataN указатель *ptr ведет в область кучи, где динамически выделена память.
Примечание: На самом деле не всегда стек и куча расположены в одной зоне памяти, физически для более быстрого выполнения стек может быть перенесен в область кэш (cash) процессора (эта память обычно существенно быстрее оперативной), но за счет адресации и работы ide данные
Важно отметить, что разработчик сам выделяет память в куче, чем может ограничить работу других программ, в C++ компилятор не отслеживает выделение памяти пользователем и указатели/ссылки на нее, поэтому если указатель будет утерян (удален), то область в куче так и останется выделенной до перезапуска программы/ перезапуска вычислителя.
Данный механизм потери памяти из-за потери указателя называется утечками leaks.
Если утечек будет много – память закончится и код не сможет выполняться.

