Не удается освободить память после использования strdup - PullRequest
3 голосов
/ 16 декабря 2010

gcc 4.5.1 c89

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

У меня есть следующая структура:

typedef struct tag_cand_results {
    char *candidate_winners[NUMBER_OF_CANDIDATES];
} cand_results;

Я создаю объект этой структуры:

cand_results *results = NULL;

Я выделяю память для структуры.

results = calloc(1, sizeof *results);

Назначить ему некоторые данные

results->candidate_winners[0] = strdup("Steve Martin");
results->candidate_winners[1] = strdup("Jack Jones");

Затем я пытаюсь освободить всю выделенную память:

free(results->candidate_winners[0]);
free(results->candidate_winners[1]);
free(results);

Just to be safe assign to NULL
results = NULL;

Я получаю следующий вывод из valgrind.

==8119== 72 bytes in 6 blocks are definitely lost in loss record 1 of 2
==8119==    at 0x4A05E46: malloc (vg_replace_malloc.c:195)
==8119==    by 0x3FE2E82A91: strdup (strdup.c:43)
==8119==    by 0x400E5A: main (driver.c:116)
==8119== 
==8119== 72 bytes in 6 blocks are definitely lost in loss record 2 of 2
==8119==    at 0x4A05E46: malloc (vg_replace_malloc.c:195)
==8119==    by 0x3FE2E82A91: strdup (strdup.c:43)
==8119==    by 0x400E72: main (driver.c:117)

Не знаю, почему память не была освобождена?

Большое спасибо за любые предложения,

Ответы [ 4 ]

4 голосов
/ 16 декабря 2010

Если это на самом деле последовательность событий, то valgrind неверен. Память освобождается .


Что касается лучшего метода, запрошенного в вашем комментарии, обычно я бы сказал, valgrind, но, возможно, не в этом случае: -)

Некоторые вещи, которые нужно проверить.

  • Что произойдет, если вы просто позвоните malloc(30) вместо strdup(some_string) (в обоих случаях)?
  • Удалите (malloc-or-strdup)/free pairs по одному, чтобы увидеть, что происходит.
  • Я не видел ваш настоящий код, поэтому поместите printf до и после каждой строки strdup и free, чтобы убедиться, что все они запускаются.
  • Опубликуйте здесь полную небольшую программу (которая показывает проблему), чтобы мы могли проверить ее.

Для чего стоит следующая маленькая (полная) программа:

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

#define NUMBER_OF_CANDIDATES 10
typedef struct tag_cand_results {
    char *candidate_winners[NUMBER_OF_CANDIDATES];
} cand_results;

int main (void) {
    cand_results *results = NULL;

    results = calloc(1, sizeof *results);

    results->candidate_winners[0] = strdup("Steve Martin");
    results->candidate_winners[1] = strdup("Jack Jones");

    free(results->candidate_winners[0]);
    free(results->candidate_winners[1]);
    free(results);

    results = NULL;

    return 0;
}

приводит к следующему выводу valgrind:

==9649== Memcheck, a memory error detector
==9649== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==9649== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for
         copyright info
==9649== Command: ./qq
==9649== 
==9649== 
==9649== HEAP SUMMARY:
==9649==     in use at exit: 0 bytes in 0 blocks
==9649==   total heap usage: 3 allocs, 3 frees, 64 bytes allocated
==9649== 
==9649== All heap blocks were freed -- no leaks are possible
==9649== 
==9649== For counts of detected and suppressed errors, rerun with: -v
==9649== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 8)

Другими словами, проблем нет. Так что это может быть что-то еще в вашем случае (возможно, проблема окружающей среды). Этот конкретный прогон был выполнен в Ubuntu Lucid (10.04), gcc 4.4.3, c89 mode.

Я бы предложил ввести этот код точно в вашей системе, чтобы посмотреть, что произойдет. Командная строка, которую я использовал для компиляции и тестирования, была:

gcc -std=c89 -o qq qq.c
valgrind ./qq
2 голосов
/ 16 декабря 2010

Вы также можете отлаживать ваше приложение с помощью gdb и наблюдать, если какой-либо указатель изменяется с помощью команды "watch".Поместите точку останова в вашу основную функцию и выполните пошаговое наблюдение, чтобы выяснить, где находится проблема.

С уважением,

Мигель

2 голосов
/ 16 декабря 2010

Нет явных ошибок в ваших распределениях / освобождениях.

Похоже, что содержимое результата было как-то изменено (перезаписано каким-то диким указателем?).

Один простой способпроверьте, что нужно печатать значения адресов памяти указателя (используя printf ("% p", ...)) сразу после выделения с использованием strdup и непосредственно перед освобождением.Если это изменилось: bingo!

Сделайте это также с результатом, другим объяснением может быть то, что указатель на результат изменился (и впредь значения, на которые указывает).

Теперь, если указатель имеетдействительно изменилось, как точно определить, где это происходит?

Одним из решений может быть запуск программы с использованием отладчика.В некоторых случаях это может занять много времени, но обычно это работает.Но если это не вариант, есть другой способ.Я обычно нахожу это быстрее, чем использую отладчик.

Сохраняйте копию выделенного указателя в другой переменной, желательно, чтобы она была удалена от фрагмента памяти, где находится ваш поврежденный указатель (обычно это делает глобальный).

Теперь в потоке управления добавьте утверждения вроде:

assert (result == сохраненный_результат);

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

В обратном направлении, вы не должны забывать удалять свои утверждения, которые не следует оставлять в окончательном проекте.Чтобы быть уверенным в этом, просто удалите переменную save_result.Программа не будет компилироваться в режиме отладки, если осталось какое-либо утверждение.

1 голос
/ 16 декабря 2010

"72 байта в 6 блоках", не похоже на "Стива Мартина" или "Джека Джонса". Вы не перезаписываете указатели в какой-то момент (!)?

...