exponenta event banner

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

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

Описание

Утечка памяти происходит, когда вы не освобождаете блок от памяти, выделенной через 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