Pergunta

Por favor, ajude :) OS:Linux

Onde em " sleep(1000);", neste momento "top (exibir tarefas do Linux)" me escreveu 7,7% de uso de MEM.valgrind :não encontrado vazamento de memória.

Eu entendo, escrevi corretamente e todo o resultado do malloc é NULL.Mas por que neste tempo "dormir" meu programa NÃO diminuiu a memória?O que falta?

Desculpe pelo meu inglês ruim, obrigado


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

Fonte completa: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;
}
Foi útil?

Solução

Se você está tentando estabelecer se o seu programa tem vazamento de memória, então top não é a ferramenta certa para o trabalho (valrind é).

top mostra o uso de memória conforme visto pelo sistema operacional.Mesmo se você ligar free, não há garantia de que a memória liberada será devolvida ao sistema operacional.Normalmente, isso não aconteceria.No entanto, a memória torna-se "livre" no sentido de que o seu processo pode utilizá-la para alocações subsequentes.

editar Se seu libc suporta, você pode tentar experimentar M_TRIM_THRESHOLD.Mesmo se você seguir esse caminho, será complicado (um único bloco usado próximo ao topo da pilha impediria que toda a memória livre abaixo dele fosse liberada para o sistema operacional).

Outras dicas

Por boas razões, praticamente nenhum alocador de memória retorna blocos ao sistema operacional


A memória só pode ser removida do seu programa em unidades de páginas, e é improvável que isso seja observado.

calloc(3) e malloc(3) interagem com o kernel para obter memória, se necessário.Mas muito poucas implementações de free(3) retornam memória para o kernel1, eles apenas o adicionam a uma lista gratuita que calloc() e malloc() consultarão posteriormente para reutilizar os blocos liberados.Existem boas razões para esta abordagem de design.

Mesmo que um free() quisesse retornar memória ao sistema, seria necessário pelo menos uma página de memória contígua para que o kernel realmente protegesse a região, portanto, liberar um pequeno bloco só levaria a uma alteração de proteção se fosse o durar pequeno bloco em uma página.

Teoria de Operação

Portanto, malloc(3) obtém memória do kernel quando necessário, em última análise, em unidades de múltiplos de páginas discretos.Estas páginas são divididas ou consolidadas conforme a necessidade do programa.Malloc e free cooperam para manter um diretório.Eles unem blocos livres adjacentes quando possível para poder fornecer blocos grandes.O diretório pode ou não envolver o uso da memória em blocos liberados para formar uma lista vinculada.(A alternativa é um pouco mais de memória compartilhada e fácil de paginação, e envolve a alocação de memória especificamente para o diretório.) Malloc e free têm pouca ou nenhuma capacidade de impor acesso a blocos individuais, mesmo quando código de depuração especial e opcional é compilado em o programa.


1.O fato de muito poucas implementações de free() tentarem retornar memória ao sistema não se deve de forma alguma à negligência dos implementadores.

Interagir com o kernel é muito mais lento do que simplesmente executar o código da biblioteca, e o benefício seria pequeno.A maioria dos programas tem um consumo de memória estável ou crescente, portanto, o tempo gasto na análise do heap em busca de memória retornável seria completamente desperdiçado.Outros motivos incluem o fato de que a fragmentação interna torna improvável a existência de blocos alinhados à página, e é provável que o retorno de um bloco fragmente os blocos para ambos os lados.Finalmente, os poucos programas que retornam grandes quantidades de memória provavelmente ignorarão malloc() e simplesmente alocarão e liberarão páginas de qualquer maneira.

Geralmente free() não devolve memória física ao sistema operacional, eles ainda são mapeados na memória virtual do seu processo.Se você alocar uma grande quantidade de memória, a libc poderá alocá-la por mmap();então, se você liberá-lo, a libc poderá liberar a memória para o sistema operacional por munmap(); nesse caso, top mostrará que o uso de memória diminui.

Portanto, se você não quiser liberar memória explicitamente para o sistema operacional, poderá usar mmap()/munmap().

Quando você free() memória, ela é retornada ao pool de memória da biblioteca C padrão e não retornada ao sistema operacional.Na visão do sistema operacional, como você o vê através top, o processo ainda está "usando" essa memória.Dentro do processo, a biblioteca C foi responsável pela memória e poderia retornar o mesmo ponteiro de malloc() no futuro.

Vou explicar um pouco mais com um começo diferente:

Durante suas ligações para malloc, a implementação da biblioteca padrão pode determinar que o processo não possui memória alocada suficiente do sistema operacional.Nesse momento, a biblioteca fará uma chamada de sistema para receber mais memória do sistema operacional para o processo (por exemplo, sbrk() ou VirtualAlloc() chamadas de sistema no Unix ou Windows, respectivamente).

Após a biblioteca solicitar memória adicional do sistema operacional, ela adiciona essa memória à sua estrutura de memória disponível para retornar de malloc.Mais tarde liga para malloc usará essa memória até que ela acabe.Então, a biblioteca solicita ainda mais memória ao sistema operacional.

Quando você free memória, a biblioteca geralmente não retorna a memória para o sistema operacional.Há muitas razões para isto.Uma razão é que o autor da biblioteca acreditou que você ligaria malloc de novo.Se você não vai ligar malloc novamente, seu programa provavelmente terminará em breve.De qualquer forma, não há muita vantagem em devolver a memória ao sistema operacional.

Outra razão pela qual a biblioteca pode não devolver a memória ao sistema operacional é que a memória do sistema operacional é alocada em intervalos grandes e contíguos.Ele só poderia ser retornado quando um intervalo contíguo inteiro não estivesse mais em uso.O padrão de chamada malloc e free pode não limpar toda a gama de uso.

Dois problemas:

  • Em make_cache_db(), a linha

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

    provavelmente deveria ler

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

    Caso contrário, você alocará apenas um único cache_db_s nó.

  • A maneira como você está atribuindo cache_db em make_cache_db() parece estar cheio de bugs.Parece que sua intenção é retornar um ponteiro para o primeiro elemento da lista vinculada;mas porque você está reatribuindo cache_db em cada iteração do loop, você acabará retornando um ponteiro para o durar elemento da lista.

    Se mais tarde você liberar a lista usando free_cache_db(), isso fará com que você vaze memória.No momento, porém, esse problema é mascarado pelo bug descrito no ponto anterior, que faz com que você aloque listas de comprimento apenas 1.

Independente desses bugs, o ponto levantado pelo aix é muito válido:A biblioteca de tempo de execução não precisa retornar todos free()d memória para o sistema operacional.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top