Утечка памяти

Память, выделенная динамически не освобожденный

Описание

Утечка памяти происходит, когда вы не освобождаете блок от памяти, выделенной через malloc, calloc, realloc или new. Если память выделяется в функции, дефект не происходит если:

  • В функции вы освобождаете память с помощью free или delete.

  • Функция возвращает указатель, присвоенный malloc, calloc, realloc или new.

  • Функция хранит указатель в глобальной переменной или в параметре.

Риск

Функции динамического выделения памяти, такие как malloc выделяют память на куче. Если вы не выпускаете память после использования, вы уменьшаете объем памяти, доступный для другого выделения. На встраиваемых системах с ограниченной памятью вы можете закончить тем, что исчерпали доступную память кучи даже во время выполнения программы.

Фиксация

Определите осциллограф, где к динамически выделенной памяти получают доступ. Освободите блок памяти в конце этого осциллографа.

Чтобы освободить блок от памяти, используйте функцию free на указателе, который использовался во время выделения памяти. Например:

ptr = (int*)malloc(sizeof(int));
...
free(ptr);

Это - хорошая практика, чтобы выделить и освободить память в том же модуле на том же уровне абстракции. Например, в этом примере, func выделяет и освобождает память на том же уровне, но func2 не делает.

void func() {
  ptr = (int*)malloc(sizeof(int));
  {
    ...
  }
  free(ptr);
}

void func2() {
  {
   ptr = (int*)malloc(sizeof(int));
   ...
  }
  free(ptr);
}
См. правило MEM00-C CERT-C.

Примеры

развернуть все

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

void assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
         printf("Memory allocation failed");
         return;
        }


    *pi = 42;
    /* Defect: pi is not freed */
}

В этом примере pi динамически выделяется malloc. Функциональный assign_memory не освобождает память, и при этом это не возвращает pi.

Исправление — свободная память

Одно возможное исправление должно освободить память, на которую ссылается pi с помощью функции free. Функция free должна быть вызвана, прежде чем функциональный assign_memory останавливается

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

void assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
         printf("Memory allocation failed");
         return;
        }
    *pi = 42;

    /* Fix: Free the pointer pi*/
    free(pi);                   
}

Исправление — возвращает указатель в динамическое выделение

Другое возможное исправление должно возвратить указатель pi. Возврат pi позволяет функцию, вызывая assign_memory, чтобы освободить блок памяти с помощью pi.

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

int* assign_memory(void)
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) 
        {
            printf("Memory allocation failed");
            return(pi);
        }
    *pi = 42;

    /* Fix: Return the pointer pi*/
    return(pi);                   
}
#define NULL '\0'

void initialize_arr1(void)
{
    int *p_scalar = new int(5);
}

void initialize_arr2(void)
{
    int *p_array = new int[5];
}

В этом примере функции создают две переменные, p_scalar и p_array, с помощью ключевого слова new. Однако функции заканчиваются, не очищая память для этих указателей. Поскольку функции использовали new, чтобы создать эти переменные, необходимо очистить их память путем вызова delete в конце каждой функции.

Исправление — добавляет, удаляют

Чтобы исправить эту ошибку, добавьте оператор delete для каждой инициализации new. Если бы вы использовали скобки [], чтобы инстанцировать переменной, необходимо вызвать, удаляют со скобками также.

#define NULL '\0'

void initialize_arrs(void)
{
    int *p_scalar = new int(5); 
    int *p_array = new int[5];  

    delete p_scalar;
    p_scalar = NULL;

    delete[] p_array;
    p_scalar = NULL;
}

Проверяйте информацию

Группа: Динамическая память
Язык: C | C++
Значение по умолчанию: 'off'
Синтаксис командной строки: MEM_LEAK
Влияние: носитель
ID CWE: 401, 404

Введенный в R2013b