Основы программирования в Linux
Если вы повторите попытку, но не будете использовать библиотеку GNU С, вы обнаружите, что безадресное чтение не разрешено. Далее приведена программа memory5b.c:
#include <unistd.h>#include <stdlib.h>#include <stdio.h>int main() {char z = *(const char *)0;printf("I read from location zero\n");exit(EXIT_SUCCESS);}Вы получите следующий результат:
$ <b>./memory5b</b>Segmentation faultВ этот раз вы пытаетесь прочесть непосредственно из нулевого адреса. Между вами и ядром теперь нет GNU-библиотеки libc, и программа прекращает выполнение. Имейте в виду, что некоторые системы UNIX разрешают читать из нулевого адреса, ОС Linux этого не допускает.
Освобождение памяти
До сих пор мы выделяли память и затем надеялись на то, что по завершении программы использованная нами память не будет потеряна, К счастью, система управления памятью в ОС Linux вполне способна с высокой степенью надежности гарантировать возврат памяти в систему по завершении программы. Но большинство программ просто не хотят распределять память, используют ее очень короткий промежуток времени и затем завершаются. Гораздо более распространено динамическое использование памяти по мере необходимости.
Программы, применяющие память на динамической основе, должны всегда возвращать неиспользованную память диспетчеру распределения памяти
с помощью вызоваmalloc. Это позволяет выделить блоки, нуждающиеся в повторном объединении, и дает возможность библиотекеfreeследить за памятью, вместо того, чтобы заставлять приложение управлять ею. Если выполняющаяся программа (процесс) использует, а затем освобождает память, эта освободившаяся память остается выделенной процессу. За кадром система Linux управляет блоками памяти, которые программист использует как набор физических "страниц" в памяти, размером 4 Кбайт каждая. Но если страница памяти в данный момент не используется, диспетчер управления памятью ОС Linux сможет переместить ее из оперативной памяти в область свопинга (это называется обменом страниц), где она слабо влияет на потребление ресурсов. Если программа пытается обратиться к данным на странице, которая была перенесена в область свопинга, Linux на очень короткое время приостанавливает программу, возвращает страницу обратно из области свопинга в физическую память и затем разрешает программе продолжить выполнение так, будто данные все время находились в оперативной памяти.malloc<b>#include <stdlib.h></b><b>void free(void *ptr_to_memory);</b>Вызов
следует выполнять только с указателем на память, выделенную с помощью вызоваfree,mallocилиcalloc. Очень скоро вы встретитесь с функциямиreallocиcalloc. А сейчас выполните упражнение 7.6.reallocУпражнение 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);}Вывод программы следующий:
$ <b>./memory6</b>Memory allocated and freed againКак это работает
Эта программа просто показывает, как вызвать функцию
с указателем, направленным на предварительно выделенную область памяти.freeПримечаниеПомните о том, что после вызова
для освобождения блока памяти этот блок больше не принадлежит процессу. Он больше не управляется библиотекойfree. Никогда не пытайтесь читать из области памяти или писать в область памяти, для которой была вызвана функцияmalloc.freeДругие функции распределения памяти
Две другие функции распределения или выделения памяти
иcallocприменяются не так часто, какreallocиmalloc.freeДалее приведены их прототипы:
<b>#include <stdlib.h></b><b>void *calloc(size_t number_of_elements, size_t element_size);</b><b>void *realloc(void *existing_memozy, size_t new_size);</b>Несмотря на то, что функция
выделяет память, которую можно освободить с помощью функцииcalloc, ее параметры несколько отличаются от параметров функцииfree: она выделяет память для массива структур и требует задания количества элементов и размера каждого элемента массива как параметров. Выделенная память заполняется нулями; и если функцияmallocзавершается успешно, возвращается указатель на первый элемент. Как и в случае функцииcalloc, последовательные вызовы не гарантируют возврата непрерывной области памяти, поэтому вы не можете увеличить длину массива, созданного функциейmalloc, просто повторным вызовом этой функции и рассчитывать на то, что второй вызов вернет память, добавленную в конец блока памяти, полученного после первого вызова функции.callocФункция
изменяет размер предварительно выделенного блока памяти. Она получает в качестве параметра указатель на область памяти, предварительно выделенную функциямиrealloc,mallocилиcalloc, и уменьшает или увеличивает эту область в соответствии с запросом. Функция бывает вынуждена для достижения результата в перемещении данных, поэтому важно быть уверенным в том, что к памяти, выделенной после вызоваrealloc, вы всегда обращаетесь с помощью нового указателя и никогда не используете указатель, установленный ранее до вызова функцииrealloc.realloc