Освобождение динамической структуры не освобождает память - PullRequest
0 голосов
/ 14 сентября 2011
    Environment: uname -a: 2.6.38 #18 Thu Apr 28 12:38:48 CEST 2011 armv5tejl GNU/Linux
    GCC: 
     gcc -v
    Using built-in specs.
    Target: arm-linux-gnueabi
    Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-sjlj-exceptions --enable-checking=release --build=arm-linux-gnueabi --host=arm-linux-gnueabi --target=arm-linux-gnueabi
    Thread model: posix
    gcc version 4.4.5 (Debian 4.4.5-8)

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

Я говорю «очевидно», понимая, что сборщик мусора будет действовать в любое время, когда пожелает.Тем не менее, поскольку я вижу, что RSS увеличивается постепенно, когда мой тестовый код выполняется, и поскольку он выделяет одинаковое количество места в каждом тесте, я должен подумать, что распределение будет использовано повторно.

Мой код реализует простойдинамическая структура:

struct _aemErrors
{
    int stored; // true = stored to sql
    int mailed; // true = mailed to alert
    int nType;  // LOG_DEBUG LOG_INFO... 
    int time;   // error triggered timestamp
    int line;   // line in file that triggered
    char *cFunction;    // function that triggered
    char *cDesc;    // description of problem
};
struct _aemErrors **aemErrors;
int aemErrorsCount;

Структура имеет два указателя на символы, которые, при использовании, создаются с помощью malloc () или strdup ()

Каждая запись структуры инициализируется следующим образом:

int AddaemError(void)
{
    ++aemErrorsCount;
    aemErrors = (struct _aemErrors **)realloc(aemErrors, (aemErrorsCount+1) *     sizeof(struct _aemErrors *));
    aemErrors[aemErrorsCount] = (struct _aemErrors *)malloc(sizeof(struct _aemErrors));
    return(aemErrorsCount);
}

Итак:

int main(int argc,char **argv) 
{  

  // initialize the structure
  aemErrors=NULL;
  aemErrorsCount=-1;

  int nPtr=0;
  int nLoopCount=0;
  while (nLoopCount<100)
  {

    for (nPtr=0;nPtr<1000;nPtr++)
      {
      nPtr=AddaemError();
      aemErrors[nPtr]->stored=false;
      aemErrors[nPtr]->mailed=false;
      aemErrors[nPtr]->nType=LOG_ALERT;
      aemErrors[nPtr]->nTime=time(NULL);
      aemErrors[nPtr]->line=0;
      aemErrors[nPtr]->cFunction=strdup("ThisIsATest");
      aemErrors[nPtr]->cDesc=strdup("ThisIsATest");
    }
    FreeaemErrors();
    sleep(5);
    ++nLoopCount;
  }
  return(0);
}

По мере вращения цикла я вижу, как RSS растет соответствующим образом.Я использую тестер состояния внутренней памяти (не показан: читает данные файловой системы proc), а также использую процесс внешней оболочки, который инкапсулирует среду выполнения и дает мне данные о производительности памяти каждую секунду.Примечание: проблема возникает без мониторинга, поэтому я знаю, что это не влияет на результат.

Теперь я хочу освободить все:

// cleanup the dynamic structure
int FreeaemErrors(void)
{
    if (aemErrors==NULL)
        return(true);
    int i=0;

    printf("FreeaemErrors():Count=%i\n",aemErrorsCount);

    for(i = 0; i <= aemErrorsCount; i++)
    {
        free(aemErrors[i]->cFunction);
        free(aemErrors[i]->cDesc);
        free(aemErrors[i]);
        aemErrors[i]->cFunction=NULL;
        aemErrors[i]->cDesc=NULL;
        aemErrors[i]=NULL;
    }
    printf("Done.  Free root\n");
    free(aemErrors);
    aemErrors=NULL;
    aemErrorsCount=-1;
    printf("Returning\n");
    return(true);
}

Поэтому я запускаю FreeaemErrors ();а затем подождите несколько секунд, наблюдая за памятью.Он не уменьшается.

И в следующий раз, когда я запускаю цикл заполнения, добавляя еще 1000 записей к предположительно чистой структуре, RSS снова поднимается.

В настоящий момент я несколько озадачен.

Идеи, кто-нибудь?


Спасибо за ваш вклад здесь.

После довольно большого тестирования с различными размерами конструкции, я обнаружил, что как только мы достигаем определенногоразмер, а затем все бесплатно, RSS возвращается почти туда, где я ожидал.Но не совсем.

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

Реагирование на эту проблему включало (а) инициализацию размера моей структуры для хранения блока из n элементов (от 40 до 100, в зависимости от потребностей);(б) когда структура должна расти (у нас закончилось начальное распределение), я делаю копию исходной структуры, полностью освобождаю исходную, затем выделяю новую с размером n + increment_size, затем инициализирую новую изстарый, то освободи старый.В случае, когда новый запрос записи находится в пределах количества выделений, моя функция возвращает текущий номер выделения.

Новая схема вообще не использует realloc ().Учитывая проблему, я считаю это плюсом.

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

1 Ответ

1 голос
/ 14 сентября 2011

Освобождение памяти с помощью free или realloc вовсе не означает, что она возвращается в систему.Механизм кучи просто хранит эти страницы где-нибудь, чтобы они были доступны для следующего размещения.Если вы действительно хотите знать, правильно ли вы освобождаете всю свою память, используйте такой инструмент, как valgrind.Это скажет вам "postmortem", если ваш процесс освободил всю выделенную память, или, если нет, он укажет вам места в вашем коде, которые выделяются без освобождения впоследствии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...