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

#include

void free(void *ptr);

Фактически функция 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

Перейти на страницу:

Похожие книги