Функция free() высвобождает блок памяти, указанный в ее аргументе ptr, который должен быть адресом, ранее возвращенным функцией malloc() или одной из других функций выделения памяти в куче, которые будут рассмотрены далее в этой главе.
#include
void free(void *
Фактически функция free() не сдвигает вниз крайнюю точку программы, а вместо этого добавляет блок памяти к списку свободных блоков, которые будут снова использованы при дальнейших вызовах функции malloc(). Это делается по следующим причинам.
• Высвобождаемый блок памяти обычно находится где-нибудь в середине кучи, а не в ее конце, поэтому сдвинуть вниз крайнюю точку программы не представляется возможным.
• Это помогает свести к минимуму количество системных вызовов sbrk(), используемых программой. (Как уже отмечалось в разделе 3.1, системные вызовы приводят к небольшим, но все же существенным издержкам.)
• Во многих случаях сдвиг вниз крайней точки программы не поможет программам, выделяющим большие объемы памяти, поскольку они обычно имеют склонность удерживать выделенную память или многократно высвобождать и заново выделять память, а не высвобождать всю ее целиком, и после этого продолжать свое выполнение в течение длительного периода времени.
Если аргумент, предоставляемый функции free(), является NULL-указателем, то при ее вызове ничего не происходит. (Иными словами, предоставление функции free() NULL-указателя не будет ошибкой.)
Какое-либо использование аргумента ptr после вызова free(), например повторная передача значения этого аргумента функции free(), является ошибкой, которая может привести к непредсказуемым результатам.
Пример программы
Программа в листинге 7.1 может использоваться для иллюстрации того, как вызов функции free() влияет на крайнюю точку программы. Эта программа выделяет несколько блоков памяти, а затем высвобождает некоторые из них или все блоки, в зависимости от применения необязательных аргументов командной строки.
Первые два аргумента командной строки указывают количество и размер выделяемых блоков. Третий аргумент командной строки указывает шаг цикла, используемый при высвобождении блоков памяти. Если здесь указать 1 (это значение используется по умолчанию, если аргумент опущен), программа высвобождает все блоки памяти. Если указать 2, высвобождается каждый второй выделенный блок и т. д. Четвертый и пятый аргументы командной строки указывают диапазон блоков, намеченных к высвобождению. Если эти аргументы опущены, высвобождаются все выделенные блоки (с шагом, заданным в третьем аргументе командной строки).
Листинг 7.1. Демонстрация происходящего с крайней точкой программы при высвобождении памяти
memalloc/free_and_sbrk.c
#define _BSD_SOURCE
#include "tlpi_hdr.h"
#define MAX_ALLOCS 1000000
int
main(int argc, char *argv[])
{
char *ptr[MAX_ALLOCS];
int freeStep, freeMin, freeMax, blockSize, numAllocs, j;
printf("\n");
if (argc < 3 || strcmp(argv[1], "-help") == 0)
usageErr("%s num-allocs block-size [step [min [max]]]\n", argv[0]);
numAllocs = getInt(argv[1], GN_GT_0, "num-allocs");
if (numAllocs > MAX_ALLOCS)
cmdLineErr("num-allocs > %d\n", MAX_ALLOCS);
blockSize = getInt(argv[2], GN_GT_0 | GN_ANY_BASE, "block-size");
freeStep = (argc > 3)? getInt(argv[3], GN_GT_0, "step"): 1;
freeMin = (argc > 4)? getInt(argv[4], GN_GT_0, "min"): 1;
freeMax = (argc > 5)? getInt(argv[5], GN_GT_0, "max"): numAllocs;
if (freeMax > numAllocs)
cmdLineErr("free-max > num-allocs\n");
printf("Initial program break: %10p\n", sbrk(0));
printf("Allocating %d*%d bytes\n", numAllocs, blockSize
for (j = 0; j < numAllocs; j++) {
ptr[j] = malloc(blockSize);
if (ptr[j] == NULL)
errExit("malloc");
}
printf("Program break is now: %10p\n", sbrk(0));
printf("Freeing blocks from %d to %d in steps of %d\n",
freeMin, freeMax, freeStep);
for (j = freeMin — 1; j < freeMax; j += freeStep)
free(ptr[j]);
printf("After free(), program break is: %10p\n", sbrk(0));
exit(EXIT_SUCCESS);
}
memalloc/free_and_sbrk.c
Запуск программы из листинга 7.1 со следующей командной строкой приведет к выделению 1000 блоков памяти, а затем к высвобождению каждого второго блока:
$ ./free_and_sbrk 1000 10240 2
Информация, выведенная на экран, показывает, что после высвобождения этих блоков крайняя точка программы осталась на том же уровне, который был достигнут после выделения всех блоков памяти:
Initial program break: 0x804a6bc
Allocating 1000*10240 bytes
Program break is now: 0x8a13000
Freeing blocks from 1 to 1000 in steps of 2
After free(), program break is: 0x8a13000
В следующей командной строке указывается, что должны быть высвобождены все выделенные блоки, кроме последнего. В данном случае крайняя точка программы также остается на своей отметке «наивысшего поднятия уровня».
$ ./free_and_sbrk 1000 10240 1 1 999
Initial program break: 0x804a6bc
Allocating 1000*10240 bytes
Program break is now: 0x8a13000