Ответ 1
Ответ на этот вопрос довольно сложный, поскольку существуют различные подходы к распределению памяти в зависимости от области видимости переменной, размера и среды программирования.
Выделенные переменные
Обычно local variables
помещаются в "стек". Это означает, что компилятор присваивает смещение "указателю стека", который может быть различным в зависимости от вызова текущей функции. То есть компилятор предполагает, что места памяти, такие как Stack-Pointer + 4, Stack-Pointer + 8 и т.д., доступны и могут использоваться программой. При использовании return
от функции не сохраняются эти ячейки памяти.
Это сопоставляется с инструкциями по сборке, аналогичными приведенным ниже. esp
- указатель стека, esp + N
относится к ячейке памяти относительно esp:
mov eax, DWORD PTR SS:[esp]
mov eax, DWORD PTR SS:[esp + 4]
mov eax, DWORD PTR SS:[esp + 8]
Heap
Затем существуют переменные, выделенные в кучу. Это означает, что есть вызов библиотеки для запроса памяти из стандартной библиотеки (alloc
в C или new
в С++). Эта память сохраняется до конца выполнения программ. alloc
и new
возвращают указатели в память в области памяти, называемой кучей. Функции распределения должны быть уверены, что память не зарезервирована, что может замедлить распределение кучи в разы. Кроме того, если вы не хотите исчерпывать память, вы должны free
(или delete
) память, которая больше не используется. Распределение кучи довольно сложно внутри, поскольку стандартная библиотека должна отслеживать используемые и неиспользуемые диапазоны в памяти, а также освобожденные диапазоны памяти. Поэтому даже освобождение переменной, распределенной по кучам, может быть более трудоемким, чем выделение. Для получения дополнительной информации см. Как встроено malloc() внутри?
Понимание разницы между стеком и кучей имеет фундаментальное значение для обучения программированию на C и С++.
Произвольные указатели
Наивно можно предположить, что путем установки указателя на произвольный адрес int *a = 0x123
должно быть возможно адресовать произвольные местоположения в памяти компьютера. Это не совсем верно, поскольку (в зависимости от CPU и системы) программы сильно ограничены при обращении к памяти.
Получение информации о памяти
В опыте с опытным руководством может быть полезно изучить некоторые простые C-коды, скомпилировав исходный код на ассемблер (например, gcc может это сделать). Простую функцию, такую как int foo(int a, int b) { return a+b;}
, должна быть достаточной (без оптимизации). Затем увидите что-то вроде int bar(int *a, int *b) { return (*a) + (*b);}
;
При вызове bar выделите параметры один раз в стеке, один раз за malloc.
Заключение
Компилятор выполняет некоторую переменную placment и выравнивание по отношению к базовым адресам, которые получаются библиотекой программ/стандартных во время выполнения.
Для глубокого понимания вопросов, связанных с памятью, см. Ульрих Дреппер "Что каждый программист должен знать о памяти" http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.91.957
Помимо C-ish Country idenote
Тогда также есть коллекция Garbage Collection, которая популярна среди множества языков сценариев (Python, Perl, Javascript, lisp) и независимых от устройства сред (Java, С#). Это связано с распределением кучи, но немного сложнее.
Разновидности языков программирования - это только кучи (без стекового питона) или полностью основанные на стеке (вперед).