Pmonline.ru

Пром Онлайн
6 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Разница между статическим распределением памяти и динамическим распределением памяти

Разница между статическим распределением памяти и динамическим распределением памяти

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

Не могли бы вы объяснить это на каком-либо примере?

Существует три типа размещения — статическое, автоматическое и динамическое.

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

Автоматическое выделение памяти происходит для (нестатических) переменных, определенных внутри функций, и обычно хранится в stack (хотя стандарт C не требует использования стека). Вам не нужно резервировать дополнительную память, используя их, но, с другой стороны, вы также имеете ограниченный контроль над временем жизни этой памяти. Например: автоматические переменные в функции существуют только до ее завершения.

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

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

Это стандартный вопрос интервью:

Динамическое распределение памяти

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

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

Автоматическое распределение памяти

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

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

Статическое распределение памяти

Распределяется во время компиляции, а время жизни переменной в статической памяти равно времени жизни программы .

В C статическая память может быть выделена с помощью ключевого слова static . Область действия — только единица компиляции.

Все становится интереснее когда рассматривается ключевое слово extern . Когда переменная extern равна define, компилятор выделяет для нее память. Когда переменная extern равна Объявлен, компилятор требует, чтобы переменная была определена в другом месте. Неспособность объявить/определить переменные extern вызовет проблемы с компоновкой, в то время как невозможность объявить/определить переменные static вызовет проблемы компиляции.

Читайте так же:
Материнка asus p5ld2 se

в области действия файла статическое ключевое слово является необязательным (вне функции):

Но не в области действия функции (внутри функции):

Технически, extern и static являются двумя отдельными классами переменных в C.

Зарегистрировать память

Последний класс памяти является переменными ‘register’. Как и ожидалось, переменные регистра должны быть размещены в регистре процессора, но решение фактически остается за компилятором. Вы не можете превратить переменную регистра в ссылку, используя address-of.

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

Рекомендации:

Примечания о статическом распределении памяти

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

Может быть лучше подумать , что распределение статической памяти обрабатывается компилятором, а не выделяется во время компиляции. Например, компилятор может создать большой раздел data в скомпилированном двоичном файле, и когда программа загружается в память, адрес в сегменте data программы будет использоваться как расположение выделенной памяти. Это имеет явный недостаток — делать скомпилированный двоичный файл очень большим, если используется много статической памяти. Можно написать двоичный файл размером в несколько гигабайт, сгенерированный из менее чем полдюжины строк кода. Другим вариантом для компилятора является внедрение кода инициализации, который будет распределять память каким-либо другим способом до выполнения программы. Этот код будет отличаться в зависимости от целевой платформы и ОС. На практике современные компиляторы используют эвристику, чтобы решить, какой из этих параметров использовать. Вы можете попробовать это самостоятельно, написав небольшую C-программу, которая выделяет большой статический массив из элементов 10k, 1m, 10m, 100m, 1G или 10G. Для многих компиляторов размер двоичного файла будет расти линейно с размером массива, и после определенной точки он снова сократится, поскольку компилятор использует другую стратегию распределения.

Динамическое выделение памяти — память выделяется во время выполнения в куче. Это используется, когда объем (размер) памяти является переменным и известен только во время выполнения. Динамическое размещение достигается с помощью определенных функций, таких как malloc (), calloc (), realloc (), свободных в C и «new», «delete» в C++.

Статическое выделение памяти — память, выделенная во время компиляции в стеке или других сегментах данных. Это используется, когда объем (размер) памяти является статическим/постоянным и известен во время компиляции.

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

Динамическое распределение памяти: Он использует такие функции, как malloc () или calloc () для динамического получения памяти. Если эти функции используются для динамического получения памяти, а значения, возвращаемые этими функциями, присваиваются переменным-указателям, такие назначения известный как динамическое распределение памяти. Память определяется во время выполнения.

Читайте так же:
Для чего нужен принт сервер

Разница между СТАТИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ & ДИНАМИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ ПАМЯТИ

Память выделяется до начала выполнения программы .__ (во время компиляции).
Память выделяется при выполнении программы.

Во время выполнения никакие действия по выделению памяти или освобождению не выполняются.
Привязки памяти устанавливаются и уничтожаются во время выполнения.

Переменные остаются постоянно выделенными.
Распределяется только при активном программном блоке.

Реализовано с использованием стеков и куч.
Реализовано с использованием сегментов данных.

Указатель необходим для доступа к переменным.
Нет необходимости в динамически размещаемых указателях.

Более быстрое выполнение, чем Динамическое.
Медленное выполнение, чем статическое.

Требуется больше памяти.
Требуется меньше места в памяти.

Распределение статической памяти выделяется памяти перед выполнением программы во время компиляции Динамическое выделение памяти — это выделенная память во время выполнения программы во время выполнения.

Статическое выделение памяти. Выделенная память будет в стеке.

Динамическое распределение памяти. Выделенная память будет в куче.

и последнее должно быть free d, так как в C. нет сборщика мусора (GC).

Разница между распределением статической памяти и распределением динамической памяти

Я хотел бы знать, в чем разница между распределением статической памяти и распределением динамической памяти?

Не могли бы вы объяснить это каким-нибудь примером?

Существует три типа распределения: статическое, автоматическое и динамическое.

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

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

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

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

Это стандартный вопрос на собеседовании:

Распределение динамической памяти

Являются ли памяти , выделенные во время выполнения , используя calloc() , malloc() и друзья. Иногда также упоминается как память «кучи», хотя это не имеет ничего общего с кучей структур данных исх .

Память в куче является постоянной, пока не free() будет вызвана. Другими словами, вы контролируете время жизни переменной.

Автоматическое выделение памяти

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

Читайте так же:
Материнская плата asus m5a99x evo

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

Распределение статической памяти

Выделяется во время компиляции * , а время жизни переменной в статической памяти — это время жизни программы .

В C статическая память может быть выделена с помощью static ключевого слова. Область видимости — это только единица компиляции.

Все становится более интересным, когда рассматривается extern ключевое слово . Когда extern переменная определена, компилятор выделяет для нее память. Когда extern переменная объявляется , компилятор требует, чтобы переменная была определена в другом месте. Неспособность объявить / определить extern переменные вызовет проблемы связывания, в то время как отказ объявить / определить static переменные вызовет проблемы компиляции.

в области файла ключевое слово static не является обязательным (вне функции):

Но не в области действия функции (внутри функции):

Технически, extern и static два отдельных класса переменных в C.

* Примечания по распределению статической памяти

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

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

Например, компилятор может создать большой data раздел в скомпилированном двоичном файле, и когда программа загружается в память, адрес в data сегмент программы будет использоваться как расположение выделенной памяти. Это имеет заметный недостаток, заключающийся в том, что скомпилированный двоичный файл становится очень большим при использовании большого количества статической памяти. Можно написать двоичный файл размером в несколько гигабайт, созданный менее чем из полдюжины строк кода. Другой вариант — компилятор ввести код инициализации, который будет выделять память другим способом перед выполнением программы. Этот код будет отличаться в зависимости от целевой платформы и ОС. На практике современные компиляторы используют эвристику, чтобы решить, какой из этих вариантов использовать. Вы можете попробовать это сами, написав небольшую программу на C, которая выделяет большой статический массив из 10k, 1m, 10m, 100m, 1G или 10G элементов. Для многих компиляторов размер двоичного файла будет линейно расти вместе с размером массива и после определенной точки,

Регистровая память

Последний класс памяти — это «регистровые» переменные. Как и ожидалось, регистровые переменные должны быть размещены в регистре ЦП, но на самом деле решение остается за компилятором. Вы не можете превратить регистровую переменную в ссылку, используя адрес.

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

Динамические двумерные массивы

Динамические двумерные массивы в языке Си имеют сложный способ представления в памяти компьютера.

Читайте так же:
Монтировка видео для ютуба на компьютер

Рассмотрим одномерный массив из 10 указателей на объекты типа int:

A представляет собой указатель на указатель на int.

Кроме того, массив указателей может быть не статическим, а динамическим:

Следующий шаг сделать очень просто — по указателям, хранящимся в массиве A могут лежать не по одному значению, а по одномерному динамическому массиву таких значений.

Передача динамических двумерных массивов в функцию

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

Пример работы с динамическим двумерным массивом

#define MATRIX_HEIGHT 4
#define MATRIX_WIDTH 5

void dynamic_array_print(int **A, size_t N, size_t M)
<
for(int i = 0; i < N; i++) <
for(int j = 0; j < M; j++) <
printf(«%*d», 5, A[i][j]);
>
printf(«n»);
>
>

/*
return pointer on 2d dynamic array
!allocates memory -> to be freed later
*/
int ** dynamic_array_alloc(size_t N, size_t M)
<
int **A = (int **)malloc(N*sizeof(int *));
for(int i = 0; i < N; i++) <
A[i] = (int *)malloc(M*sizeof(int));
>
return A;
>

void dynamic_array_free(int **A, size_t N)
<
for(int i = 0; i < N; i++) <
free(A[i]);
>
free(A);
>

void dynamic_array_test(size_t N, size_t M)
<
int **A = dynamic_array_alloc(N, M);
int x = 1;
for(int i = 0; i < N; i++) <
for(int j = 0; j < M; j++) <
A[i][j] = x;
x += 1;
>
>
dynamic_array_print(A, N, M);
/*memory investigation*/
printf(«n Pointers to lines: «);
for(int **p = A; p < A + 3; p++)
printf(«%10d», (long int)*p);
printf(«n Direct memory access (dangerous. ):n»);
for(int *p = (int*)*A; p < (int*)*A + 25; p++)
printf(«%dt», *p);
dynamic_array_free(A, N);
>

int main()
<
dynamic_array_test(MATRIX_HEIGHT, MATRIX_WIDTH);
return 0;
>

Выделение памяти под динамический массив

Как видно из примера, создание такой сложной структуры как двумерный динамический массив требует множества системных вызовов по выделению памяти:

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

Правильное очищение таково:

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

Распределение динамической памяти во встроенном C

Могу ли я использовать функции malloc и delete во встроенном C? Например, у меня есть одна функция, в которой был создан указатель на структуру с функцией malloc. Эта функция возвращает адрес в оперативной памяти, и я могу это использовать. После выхода из моей функции, где была выделена память, этот указатель будет удален или эта память зарезервирована для этого, а функция удаления не будет завершена?

3 ответа

Да, вы можете использовать malloc во встроенном C. Некоторые встроенные системы имеют собственные инкапсулированные API выделения памяти. malloc () — это C lib API.

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

Читайте так же:
Материнская плата asrock h67m si

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

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

  • Вам необходимо убедиться, что компоновщик выделяет достаточно места для динамической кучи. Некоторые сценарии компоновщика могут уже автоматически выделять всю оставшуюся память в куче после стека и любых других зарезервированных выделений.
  • Возможно, вам потребуется реализовать низкоуровневые заглушки, чтобы позволить библиотеке получать доступ к памяти кучи — например, в библиотеке newlib вам необходимо реализовать sbrk_r() для правильной работы malloc() и т. Д.
  • В многопоточной системе вам может потребоваться реализовать заглушки мьютексов для обеспечения безопасного выделения кучи. Если библиотека не предоставляет такие заглушки, то malloc() / free() и т. Д. Будет небезопасно использовать в такой среде, и вам следует написать функции-оболочки, которые устанавливают блокировки извне.

Однако есть ряд причин, по которым вы можете избежать использования динамической памяти (или, по крайней мере, стандартной библиотеки, реализованной динамической памяти) во встроенной системе:

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

Как правило, вам не следует использовать malloc во встроенных системах, потому что это не имеет никакого смысла , как описано здесь . В частности, нет никакого смысла использовать его на голых металлических системах.

Единственное место, где имеет смысл использовать динамическое распределение памяти, — это крупные размещенные многопроцессорные системы, в которых несколько процессов совместно используют одну и ту же оперативную память. Если ваше определение встраиваемой системы — это смартфон или портативный компьютер Android, то да, можно использовать malloc.

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

Кроме того, почти каждый стандарт программирования встроенных систем запрещает динамическое выделение памяти.

голоса
Рейтинг статьи
Ссылка на основную публикацию