Проблема использования памяти в C - PullRequest
0 голосов
/ 13 мая 2011

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

Где в "sleep (1000);", в это время "top (отображать задачи Linux)" написали мне 7,7% MEM.valgrind: не найдена утечка памяти.

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

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

<code>
~ # 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<code>
  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    
</code>

Полный источник: 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;
}

Ответы [ 5 ]

10 голосов
/ 13 мая 2011

По понятным причинам практически никакой распределитель памяти не возвращает блоки в ОС


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

calloc (3) и malloc (3) взаимодействуют с ядром, чтобы получить память, если это необходимо. Но очень, очень немногие реализации free (3) когда-либо возвращают память ядру 1 , они просто добавляют ее в свободный список, который calloc () и malloc () будут использовать позже, чтобы повторно использовать выпущенную версию. блоки. Есть веские причины для такого подхода к проектированию.

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

Теория работы

Таким образом, malloc (3) получает память от ядра, когда это необходимо, в конечном итоге в единицах дискретных кратных страниц. Эти страницы разделены или объединены в соответствии с требованиями программы. Malloc и свободно сотрудничают, чтобы поддерживать каталог. Они объединяют смежные свободные блоки, когда это возможно, для обеспечения больших блоков. Каталог может включать или не включать использование памяти в освобожденных блоках для формирования связанного списка. (Альтернатива - чуть более совместная память и дружественная подкачка, и она включает в себя выделение памяти специально для каталога.) У Malloc и free практически отсутствует возможность принудительного доступа к отдельным блокам, даже когда специальный и дополнительный код отладки компилируется в программа.


1. Тот факт, что очень немногие реализации free () пытаются вернуть память в систему вовсе не из-за ослабления работы разработчиков.

Взаимодействие с ядром намного медленнее, чем простое выполнение библиотечного кода, и выгода будет небольшой. Большинство программ имеют постоянный или увеличивающийся объем памяти, поэтому время, затрачиваемое на анализ кучи в поисках возвратной памяти, будет полностью потрачено впустую. Другие причины включают в себя тот факт, что внутренняя фрагментация делает блоки, выровненные по страницам, маловероятными, и, вероятно, возвращение блока приведет к фрагментации блоков в любую сторону. Наконец, те немногие программы, которые возвращают большие объемы памяти, скорее всего, будут обходить malloc () и в любом случае просто выделять и освобождать страницы.

4 голосов
/ 13 мая 2011

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

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

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

2 голосов
/ 13 мая 2011

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

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

1 голос
/ 13 мая 2011

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

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

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

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

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

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

0 голосов
/ 13 мая 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 память операционной системе.

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