Organização de memória, stack, heap IV
Contato
- Jean Paulo Martins (jeanmartins utfpr edu br)
- Sala 105, Bloco S (UTFPR - Campus Pato Branco)
Conteúdo
Revisão
Organização de memória
(imagem:geeksforgeeks.org)
Pilha de chamadas
-
Região de memória utilizada para alocação de variáveis locais e passagem de parâmetros para funções
-
Alocação e desalocação de memória é feita automaticamente quando entrando/saindo do escopo de declaração das variáveis.
-
Alocar implica em inserir elementos no topo da pilha (reservar espaço no topo da pilha)
-
Desalocar implica em remover elementos do topo da pilha
Memória dinâmica:
-
Região de memória utilizada para alocação de variáveis não presas a um escopo.
-
Alocação e desalocação precisam ser requisitadas explicitamente pelo programador
-
Alocar implica em procurar na memória uma região livre do tamanho requisitado.
-
Desalocar implica em liberar região de memória previamente requisitada
Questão de revisão
-
Àqueles que já fizeram esta disciplina:
-
A pilha de chamadas é implementada como uma estrutura de dados pilha
-
Como o Heap é implementado?
-
Obs: existe uma estrutura de dados chamada Heap, porém isso é uma coincidência.
-
Gerenciamento de memória em C
Em C, memória no Heap é gerenciada pelas funções (manpage:malloc)
#include <stdlib.h>
void* malloc(size_t size);
void free(void *ptr);
void* calloc(size_t nmemb, size_t size);
void* realloc(void *ptr, size_t size);
Vazamentos de memória
Memória alocada dinâmicamente precisa ser liberada pelo programador. Analise o seguinte código:
float media_idade(){
float soma = 0;
for (int i = 0; i < NUM_PESSOAS; i++){
Pessoa* p = nova_pessoa();
ler_pessoa(p);
soma += p->idade;
}
return soma/NUM_PESSOAS;
}
int main() {
printf("%f\n", media_idade());
}
Como a memória alocada pela função nova_pessoa
não foi liberada, nem ponteiros para essas memórias mantidos, após o fim da função, não haverá como liberar essa memória.
Exemplo: malloc
// Utilizando malloc
int main() {
char* ptr;
for (int i = 0; i < 10; i++)
ptr = malloc(sizeof(char) * 1000);
free(ptr);
return 0;
}
Valgrind nos responde - Valgrind (wikipedia)
==14406== HEAP SUMMARY:
==14406== in use at exit: 9,000 bytes in 9 blocks
==14406== total heap usage: 10 allocs, 1 frees, 10,000 bytes allocated
==14406==
==14406== LEAK SUMMARY:
==14406== definitely lost: 9,000 bytes in 9 blocks
==14406== indirectly lost: 0 bytes in 0 blocks
==14406== possibly lost: 0 bytes in 0 blocks
==14406== still reachable: 0 bytes in 0 blocks
==14406== suppressed: 0 bytes in 0 blocks
Exemplo: realloc
// Utilizando realloc
int main() {
char* ptr;
for (int i = 0; i < 10; i++)
ptr = realloc(ptr, sizeof(char) * 1000);
free(ptr);
return 0;
}
Valgrind nos responde
==14322== HEAP SUMMARY:
==14322== in use at exit: 0 bytes in 0 blocks
==14322== total heap usage: 10 allocs, 10 frees, 10,000 bytes allocated
==14322==
==14322== All heap blocks were freed -- no leaks are possible
Exemplo: mantendo referências
Para que seja possível desalocar as memórias alocadas, é preciso manter um ponteiro para cada uma delas.
// Utilizando malloc
int main() {
char* ptr[10];
for (int i = 0; i < 10; i++)
ptr[i] = malloc(sizeof(char) * 10 * (i + 1));
free(ptr);
return 0;
}
Erro de compilação
A ideia deste código está correta porém a implementação está errada e nos leva a um erro de compilação, pois ptr
não está alocada no heap.
In function ‘main’:
:11:5: warning: attempt to free a non-heap object ‘ptr’ [-Wfree-nonheap-object] free(ptr);
Exercício: liberando memória
Como alterar o código acima para que toda memória seja desalocada?