Проблема использования памяти в C

Пожалуйста, помогите :) ОС: Linux

Где в "sleep(1000);", в это время "top (display Linux tasks)" у меня написано 7.7 %MEM use. valgrind: утечка памяти не обнаружена.

Я так понимаю, написал правильно и все malloc результат NULL. Но почему в это время "спит" моя программа НЕ уменьшила память? Что отсутствует?

Извините за мой плохой английский, спасибо


~ # tmp_soft
For : Is it free??  no
Is it free??  yes
For 0 
For : Is it free??  no
Is it free??  yes
For 1 
END : Is it free??  yes
END 

~ #top
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                
23060 root      20   0  155m 153m  448 S    0  7.7   0:01.07 tmp_soft    

Полный источник: tmp_soft.c

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

struct cache_db_s
{
 int       table_update;
 struct    cache_db_s * p_next;
};

void free_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t;
 while (*cache_db != NULL)
 {
  cache_db_t = *cache_db;
  *cache_db = (*cache_db)->p_next;
  free(cache_db_t);
  cache_db_t = NULL;
 }
 printf("Is it free??  %s\n",*cache_db==NULL?"yes":"no");
}

void make_cache_db (struct cache_db_s ** cache_db)
{
 struct cache_db_s * cache_db_t = NULL;
 int n = 10000000;

 for (int i=0; i = n; i++)
 {
  if ((cache_db_t=malloc(sizeof(struct cache_db_s)))==NULL) {
   printf("Error : malloc 1 -> cache_db_s (no free memory) \n");
   break;
  }
  memset(cache_db_t, 0, sizeof(struct cache_db_s));

  cache_db_t->table_update = 1; // tmp 

  cache_db_t->p_next = *cache_db;
  *cache_db = cache_db_t;
  cache_db_t = NULL;
 }
}

int main(int argc, char **argv)
{
 struct cache_db_s * cache_db = NULL;

 for (int ii=0; ii  2; ii++) {
  make_cache_db(&cache_db);
  printf("For : Is it free??  %s\n",cache_db==NULL?"yes":"no");
  free_cache_db(&cache_db);
  printf("For %d \n", ii);
 }

 printf("END : Is it free??  %s\n",cache_db==NULL?"yes":"no");
 printf("END \n");
 sleep(1000);
 return 0;
}

person Vadi    schedule 13.05.2011    source источник
comment
Ваша программа имеет некоторые ошибки, я думаю - например, for(int i = 0; i = n; i++) выглядит немного странно.   -  person Carl Norum    schedule 13.05.2011
comment
возможный дубликат Использование памяти не уменьшается при использовании бесплатного?   -  person Cory Klein    schedule 18.07.2013


Ответы (4)


Если вы пытаетесь установить, есть ли в вашей программе утечка памяти, то top не подходит для этой работы (в отличие от valrind).

top показывает использование памяти с точки зрения ОС. Даже если вы вызовете free, нет гарантии, что освобожденная память будет возвращена ОС. Как правило, нет. Тем не менее, память становится «свободной» в том смысле, что ваш процесс может использовать ее для последующих выделений.

редактировать Если ваш libc поддерживает это, вы можете попробовать поэкспериментировать с M_TRIM_THRESHOLD. Даже если вы пойдете по этому пути, это будет сложно (один использованный блок, расположенный близко к вершине кучи, предотвратит освобождение всей свободной памяти под ним для ОС).

person NPE    schedule 13.05.2011
comment
если мне не нужно для последующих выделений, так что мне нужно? - person Vadi; 13.05.2011
comment
@Vadi: я не уверен, что понимаю ваш вопрос, но чего именно вы пытаетесь достичь? Если вы хотите установить, есть ли в вашей программе утечки памяти, то top не подходит для этого. - person NPE; 13.05.2011

Как правило, free() не возвращает физическую память ОС, они по-прежнему отображаются в виртуальной памяти вашего процесса. Если вы выделяете большой кусок памяти, libc может выделить его с помощью mmap(); затем, если вы освободите его, libc может освободить память для ОС с помощью munmap(), в этом случае top покажет, что использование вашей памяти снижается.

Итак, если вы не хотите явно освобождать память для ОС, вы можете использовать mmap()/munmap().

person Huang F. Lei    schedule 13.05.2011

При free() памяти она возвращается в пул памяти стандартной библиотеки C, а не в операционную систему. В видении операционной системы, как вы видите через top, процесс все еще «использует» эту память. В процессе библиотека C учла память и может в будущем вернуть тот же указатель из malloc().

Я объясню это еще немного с другим началом:

Во время ваших вызовов malloc реализация стандартной библиотеки может определить, что процессу не хватает памяти, выделенной операционной системой. В это время библиотека сделает системный вызов, чтобы получить больше памяти от операционной системы к процессу (например, системные вызовы sbrk() или VirtualAlloc() в Unix или Windows соответственно).

После того, как библиотека запрашивает у операционной системы дополнительную память, она добавляет эту память в свою структуру памяти, доступной для возврата из malloc. Последующие вызовы malloc будут использовать эту память, пока она не закончится. Затем библиотека запрашивает у операционной системы еще больше памяти.

При free памяти библиотека обычно не возвращает память операционной системе. Существует много причин для этого. Одна из причин заключается в том, что автор библиотеки полагал, что вы снова вызовете malloc. Если вы больше не позвоните malloc, ваша программа, вероятно, скоро завершится. В любом случае нет особого смысла возвращать память операционной системе.

Другая причина, по которой библиотека может не возвращать память операционной системе, заключается в том, что память операционной системы выделяется большими непрерывными диапазонами. Его можно вернуть только тогда, когда весь непрерывный диапазон больше не используется. Шаблон вызова malloc и free может не очищать весь диапазон использования.

person Heath Hunnicutt    schedule 13.05.2011

Две проблемы:

  • В make_cache_db() строка

    for (int i=0; i = n; i++)
    

    наверное надо читать

    for (int i=0; i<n; i++)
    

    В противном случае вы выделите только один узел cache_db_s.

  • То, как вы назначаете cache_db в make_cache_db(), кажется ошибочным. Кажется, вы намерены вернуть указатель на первый элемент связанного списка; но поскольку вы переназначаете cache_db на каждой итерации цикла, вы в конечном итоге вернете указатель на последний элемент списка.

    Если вы позже освободите список с помощью free_cache_db(), это приведет к утечке памяти. Однако на данный момент эта проблема маскируется ошибкой, описанной в предыдущем пункте, из-за которой вы выделяете списки только длины 1.

Независимо от этих ошибок, точка зрения, поднятая aix, очень верна: библиотеке времени выполнения не нужно возвращать всю память free()d в операционную систему.

person Martin B    schedule 13.05.2011