C Academy · Урок

Освобождение памяти и предотвращение утечек

Корректно освобождайте ресурсы.

Урок 4 из 413 шагов

«Освобождение памяти и предотвращение утечек» — бесплатный урок C Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C Academy содержит 4 уроков всего.

Каждому malloc нужен free

Память в куче остаётся занятой, пока Вы не освободите её с помощью free. Если потерять единственный указатель на блок, не освободив его, эта память станет утечкой.

Со временем утечки накапливаются и могут исчерпать память в долго работающих программах.

int *a = malloc(100 * sizeof(*a));
/* ... use a ... */
free(a);

Что на самом деле делает free

free(p) возвращает блок распределителю памяти, чтобы его можно было использовать повторно. Значение самого p при этом не изменяется.

После вызова free p по-прежнему указывает на старый адрес, который теперь недействителен. Обращение к нему приводит к неопределённому поведению.

free(p);
/* p is now a dangling pointer */

Опасность висячего указателя

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

Простая мера защиты — сразу после освобождения установить указатель в NULL.

free(a);
a = NULL;   /* now misuse is a clean NULL deref, easier to catch */

Двойное освобождение — неопределённое поведение

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

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

free(a);
a = NULL;
free(a);   /* free(NULL) is a harmless no-op */

Освобождайте только память, выделенную через malloc

Передавайте в free только указатель, полученный из malloc, calloc или realloc.

Освобождение адреса переменной в стеке, строкового литерала или указателя на середину блока приводит к неопределённому поведению.

int x = 5;
/* free(&x);   WRONG: x is on the stack */
int *p = malloc(sizeof(int));
free(p);        /* correct */

Утечка из-за раннего возврата

Распространённая причина утечки: программа выделяет память, затем попадает в ветку обработки ошибки и возвращает управление, не освободив её. Блок теряется.

Убедитесь, что каждый путь выхода, отвечающий за эту память, сначала освобождает её.

int *a = malloc(n * sizeof(*a));
if (something_failed) {
    free(a);   /* don't forget this before returning */
    return -1;
}

Программа с корректным выделением и освобождением памяти

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

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n = 4;
    int *a = malloc(n * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < n; i++) a[i] = i + 1;
    int sum = 0;
    for (int i = 0; i < n; i++) sum += a[i];
    printf("%d\n", sum);
    free(a);
    a = NULL;
    return 0;
}

Освобождение вложенных выделений

Если блок содержит указатели на другие блоки, сначала освободите внутренние блоки, а затем внешний.

Освобождение внешнего блока первым приведёт к потере адресов внутренних блоков и утечке памяти.

for (size_t i = 0; i < rows; i++)
    free(grid[i]);   /* free each row first */
free(grid);          /* then the array of pointers */

Один владелец для каждого блока

Определите, какая часть кода владеет каждым выделенным блоком и отвечает за его освобождение.

Если два указателя ссылаются на один блок и оба освобождают его, возникает двойное освобождение. Чётко определённое владение предотвращает эту проблему.

Обнаружение утечек с помощью инструментов

Вам не нужно искать утечки вручную. Такие инструменты, как valgrind или AddressSanitizer, сообщают об утечках и недопустимых освобождениях, указывая номера строк.

Скомпилируйте программу с помощью -g и запустите её под управлением инструмента, чтобы точно узнать, что не было освобождено.

/* gcc -g -fsanitize=address prog.c && ./a.out */
/* or: valgrind --leak-check=full ./a.out */

Освобождайте ресурсы в обратном порядке подготовки

Надёжное правило: если функция получает несколько ресурсов, освобождайте их в обратном порядке.

Это отражает порядок построения зависимостей и делает очистку предсказуемой.

char *buf = malloc(64);
int  *idx = malloc(64 * sizeof(int));
/* ... use them ... */
free(idx);   /* free last-acquired first */
free(buf);

Быстрая проверка

Проверьте, насколько хорошо Вы поняли освобождение памяти.

Повторение

Для каждого выделения памяти должен быть ровно один вызов free на каждом возможном пути выполнения.

Избегайте висячих указателей и двойного освобождения, устанавливая указатели в NULL после освобождения. Освобождайте вложенные блоки изнутри наружу, назначайте каждому блоку одного владельца и используйте valgrind или санитизатор адресов для обнаружения утечек. Теперь у Вас есть полный набор инструментов для работы с динамическими массивами.

Можно начать бесплатно

Изучай C с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
39
Уроки
144

Часто задаваемые вопросы

Урок «Освобождение памяти и предотвращение утечек» бесплатный?

Да — полный текст урока «Освобождение памяти и предотвращение утечек» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C Academy, подпишись на CoddyKit PRO. Курс C Academy содержит 4 уроков всего.

Чему я научусь в уроке «Освобождение памяти и предотвращение утечек»?

Корректно освобождайте ресурсы. Ты практикуешь C Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C Academy?

Предыдущий опыт не требуется. C Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Освобождение памяти и предотвращение утечек»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C Academy?

Да. Каждый урок C Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Выделение массива
  2. Изменение размера с realloc
  3. Многоразовый тип вектора
  4. Освобождение памяти и предотвращение утечек
← Назад к C Academy