Что имеет в виду Valgrind, когда говорит, что память «определенно потеряна»? - PullRequest
0 голосов
/ 02 августа 2020

Следующая программа:

#include <stdlib.h>

int main(void)
{
    char *my_str = malloc(42 * sizeof(char));

    return 0;
}

Скомпилирована как таковая:

gcc -g -o prog prog.c

И выполнена с помощью Valgrind как таковая:

valgrind --leak-check=full ./prog

Производит следующее (усеченное ) output:

...
==18424== HEAP SUMMARY:
==18424==     in use at exit: 42 bytes in 1 blocks
==18424==   total heap usage: 1 allocs, 0 frees, 42 bytes allocated
==18424== 
==18424== 42 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18424==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18424==    by 0x10865B: main (main.c:5)
==18424== 
==18424== LEAK SUMMARY:
==18424==    definitely lost: 42 bytes in 1 blocks
==18424==    indirectly lost: 0 bytes in 0 blocks
==18424==      possibly lost: 0 bytes in 0 blocks
==18424==    still reachable: 0 bytes in 0 blocks
==18424==         suppressed: 0 bytes in 0 blocks
...

Почему Valgrind говорит, что неиспользованная память «определенно потеряна»?

Из документации Valgrind Memcheck :

Это означает, что указатель на блок не может быть найден. Блок классифицируется как «потерянный», потому что программист не мог освободить его при выходе из программы, поскольку на него не существует указателя. Скорее всего, это симптом потери указателя на каком-то более раннем этапе программы.

Однако довольно ясно, что я мог легко освободить блок до выхода из программы. Что мне здесь не хватает? Разве память не должна быть «все еще доступной»?

Ответы [ 3 ]

3 голосов
/ 02 августа 2020

Почему Valgrind говорит, что неиспользованная память «определенно потеряна»?

Потому что - однажды main возвращает переменную my_str больше не существует. Следовательно, нет возможности освободить выделенную память. И нет возможности дотянуться до памяти. Никто не знает, где память. Он утерян.

Примечание: все современные ОС, однако, позаботятся об очистке памяти, поэтому это не проблема.

3 голосов
/ 02 августа 2020

Вот пример «определенно потеряно» или «все еще достижимо»:

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

void *p;

int main()
{
    p = malloc(10);
    p = malloc(100);
    void *m = malloc(50);
    return 0;
}

В этом коде происходит следующее:

  • 10 байт выделяются и указатель на эту память назначается глобальному p.
  • 100 байт выделяются, а указатель на эту память назначается глобальному p. Это перезаписывает значение указателя, указывающее на 10 выделенных байтов, и на него больше нет ссылки. Таким образом, память «определенно потеряна».
  • 50 байт выделяются, и указатель на эту память назначается локальному m.
  • main возвращает, что приводит к времени жизни m до конца. В результате не сохраняется ссылка на указатель памяти на 50 байт, так что память «определенно потеряна».
  • Указатель значения указателя на 100 байт все еще находится в глобальном p, поэтому процедуры очистки, такие как поскольку те, которые вызываются atexit или другими методами c компилятора, могут очистить эту память. Таким образом, он «все еще доступен».

При запуске valgrind с этим кодом он выводит следующее:

==60822== Memcheck, a memory error detector
==60822== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==60822== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==60822== Command: ./x1
==60822== 
==60822== 
==60822== HEAP SUMMARY:
==60822==     in use at exit: 160 bytes in 3 blocks
==60822==   total heap usage: 3 allocs, 0 frees, 160 bytes allocated
==60822== 
==60822== LEAK SUMMARY:
==60822==    definitely lost: 60 bytes in 2 blocks
==60822==    indirectly lost: 0 bytes in 0 blocks
==60822==      possibly lost: 0 bytes in 0 blocks
==60822==    still reachable: 100 bytes in 1 blocks
==60822==         suppressed: 0 bytes in 0 blocks
==60822== Rerun with --leak-check=full to see details of leaked memory
==60822== 
==60822== For counts of detected and suppressed errors, rerun with: -v
==60822== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Что согласуется с описанием выше.

Итак, чтобы подвести итог, память «все еще доступна», если указатель на нее хранится либо в переменной области видимости файла, либо на него указывает любая «все еще доступная» память. В противном случае он будет утерян.

0 голосов
/ 02 августа 2020

Valgrind проверяет утечки памяти, и вы утекаете памятью, поскольку вы не освободили указатель перед выходом. Вы должны освободить (my_str).

int main(void)
{
    char *my_str = malloc(42 * sizeof(char));
    free (my_str);
    return 0;
}

Определенно потеряно означает, что никто больше не имеет ссылки на эту ячейку памяти, поэтому никто не может освободить эту память. В контексте запущенной программы это будет сегмент памяти, который никто не сможет повторно использовать (поэтому он будет потерян). Конечно, в конце программы никто никогда не будет использовать ее снова, но на некоторую часть памяти может ссылаться другой объект с утечкой (и это будет косвенная потеря), поэтому с этими подсказками вы можете отлаживать свою программу. По ссылке ниже показано обсуждение topi c.

Это полный ответ о том, почему вы должны освобождать память перед выходом

...