Шрифт:
Программы, применяющие память на динамической основе, должны всегда возвращать неиспользованную память диспетчеру распределения памяти
malloc
с помощью вызова free
. Это позволяет выделить блоки, нуждающиеся в повторном объединении, и дает возможность библиотеке malloc
следить за памятью, вместо того, чтобы заставлять приложение управлять ею. Если выполняющаяся программа (процесс) использует, а затем освобождает память, эта освободившаяся память остается выделенной процессу. За кадром система Linux управляет блоками памяти, которые программист использует как набор физических "страниц" в памяти, размером 4 Кбайт каждая. Но если страница памяти в данный момент не используется, диспетчер управления памятью ОС Linux сможет переместить ее из оперативной памяти в область свопинга (это называется обменом страниц), где она слабо влияет на потребление ресурсов. Если программа пытается обратиться к данным на странице, которая была перенесена в область свопинга, Linux на очень короткое время приостанавливает программу, возвращает страницу обратно из области свопинга в физическую память и затем разрешает программе продолжить выполнение так, будто данные все время находились в оперативной памяти.
#include <stdlib.h>
void free(void *ptr_to_memory);
Вызов
free
следует выполнять только с указателем на память, выделенную с помощью вызова malloc
, calloc
или realloc
. Очень скоро вы встретитесь с функциями calloc
и realloc
. А сейчас выполните упражнение 7.6. Упражнение 7.6. Освобождение памяти
Эта программа называется memory6.c.
#include <stdlib.h>
#include <stdio.h>
#define ONE_K (1024)
int main {
char *some_memory;
int exit code = EXIT_FAILURE;
some_memory = (char*)malloc(ONE_K);
if (some_memory != NULL) {
free(some_memory);
printf("Memory allocated and freed again\n");
exit_code = EXIT_SUCCESS;
}
exit(exit_code);
}
Вывод программы следующий:
$ ./memory6
Memory allocated and freed again
Как это работает
Эта программа просто показывает, как вызвать функцию
free
с указателем, направленным на предварительно выделенную область памяти. Примечание
Помните о том, что после вызова
free
для освобождения блока памяти этот блок больше не принадлежит процессу. Он больше не управляется библиотекой malloc
. Никогда не пытайтесь читать из области памяти или писать в область памяти, для которой была вызвана функция free
. Другие функции распределения памяти
Две другие функции распределения или выделения памяти
calloc
и realloc
применяются не так часто, как malloc
и free
. Далее приведены их прототипы:
#include <stdlib.h>
void *calloc(size_t number_of_elements, size_t element_size);
void *realloc(void *existing_memozy, size_t new_size);
Несмотря на то, что функция
calloc
выделяет память, которую можно освободить с помощью функции free
, ее параметры несколько отличаются от параметров функции malloc
: она выделяет память для массива структур и требует задания количества элементов и размера каждого элемента массива как параметров. Выделенная память заполняется нулями; и если функция calloc
завершается успешно, возвращается указатель на первый элемент. Как и в случае функции malloc
, последовательные вызовы не гарантируют возврата непрерывной области памяти, поэтому вы не можете увеличить длину массива, созданного функцией calloc
, просто повторным вызовом этой функции и рассчитывать на то, что второй вызов вернет память, добавленную в конец блока памяти, полученного после первого вызова функции. Функция
realloc
изменяет размер предварительно выделенного блока памяти. Она получает в качестве параметра указатель на область памяти, предварительно выделенную функциями malloc
, calloc
или realloc
, и уменьшает или увеличивает эту область в соответствии с запросом. Функция бывает вынуждена для достижения результата в перемещении данных, поэтому важно быть уверенным в том, что к памяти, выделенной после вызова realloc
, вы всегда обращаетесь с помощью нового указателя и никогда не используете указатель, установленный ранее до вызова функции realloc
. Другая проблема, за которой нужно следить, заключается в том, что функция
realloc
возвращает пустой указатель при невозможности изменить размер блока памяти. Это означает, что в приложениях следует избегать кода, подобного приведенному далее:
my_ptr = malloc(BLOCK_SIZE);
...
my_ptr = realloc(my_ptr, BLOCK_SIZE * 10);
Если
realloc
завершится аварийно, она вернет пустой указатель; переменная my_ptr
будет указывать в никуда и к первоначальной области памяти, выделенной функцией malloc
, больше нельзя будет обратиться с помощью указателя my_ptr
. Следовательно, было бы полезно сначала запросить новый блок памяти с помощью malloc
, а затем скопировать данные из старого блока памяти в новый блок с помощью функции memcpy
и освободить старый блок памяти вызовом free
. При возникновении ошибки это позволит приложению сохранить доступ к данным, хранящимся в первоначальном блоке памяти, возможно, на время организации корректного завершения программы.