Utilize Stack vs Heap Memory Allocation em C++
Este artigo explicará vários métodos de como utilizar a alocação de memória stack vs heap em C++.
Diferença entre pilha e memória heap em C++
Quando queremos discutir os conceitos de memória, é melhor pensar em termos de sistemas onde os programas de usuário mais comuns são executados. A maioria dos programas de usuário é executada em um ambiente de sistema operacional, que gerencia recursos de hardware para nós e cuida de várias tarefas que seriam muito complexas ou ineficientes para um programa de usuário realizar. Uma dessas tarefas é gerenciar a memória do hardware diretamente. Assim, quase todos os sistemas operacionais fornecem estruturas e funções especiais para interagir com a memória do hardware. Dois conceitos comuns nas estruturas de memória fornecidas pelo sistema operacional são pilha e heap.
Uma pilha é uma região da memória reservada para cada programa em execução no sistema e opera de maneira LIFO. Ou seja, quando o programa começa a executar a função main
, esta obtém seu quadro de pilha (um subconjunto da memória de pilha), onde as variáveis locais e os endereços de retorno de chamada de função são armazenados automaticamente. Uma vez que main
chama outra função, um novo quadro de pilha é criado após o anterior de maneira contínua. O quadro de pilha mais recente armazenará os objetos locais para a função correspondente e, quando retornar, essa memória ficará desocupada.
Observe que o tamanho da pilha é fixo na maioria dos sistemas por padrão, mas pode ser personalizado até certo ponto se o usuário tiver necessidades especiais. A limitação de tamanho da memória da pilha a torna adequada para objetos pequenos e principalmente temporários. Por exemplo, o tamanho da pilha padrão para o programa do usuário no sistema operacional Linux é 8 MB. Ele pode ser menor do que uma única foto JPEG que um programa pode precisar processar, portanto, o usuário deve usar esse espaço com muito cuidado. As variáveis declaradas no fragmento de código a seguir são todas armazenadas na memória da pilha. Como regra geral, cada variável local é alocada na pilha se não tiver especificadores especiais como static
ou volatile
.
#include <iostream>
using std::cout;
using std::endl;
int main() {
int var1;
int var2 = 123;
int arr1[4] = {1, 2, 3, 4};
int var3 = var2;
cout << var1 << endl;
cout << var2 << endl;
cout << var3 << endl;
return EXIT_SUCCESS;
}
Resultado:
0
123
123
Por outro lado, existe uma região de memória chamada - heap (também conhecida como free store
), onde grandes objetos podem ser armazenados e alocações feitas manualmente pelo programador durante o tempo de execução. Esses dois recursos tornam a memória heap dinâmica por natureza, já que seu tamanho não precisa ser determinado em tempo de compilação ou em qualquer momento durante a execução do programa. O programa pode chamar funções especiais e solicitar as alocações do sistema operacional. Observe que a memória heap pode parecer infinita da perspectiva do programa, pois não está limitada a chamar outra função de alocação para solicitar mais memória. Embora, o sistema operacional gerencie a memória para todos os processos em execução; e pode diminuir novas alocações quando não houver mais memória física disponível.
O sistema de memória no sistema operacional é bastante complexo e requer uma compreensão de vários conceitos específicos do SO / hardware, portanto, cobrimos apenas mais do que o mínimo sobre heap e memórias de pilha neste tópico. O gerenciamento manual da memória heap em linguagem C++ pode ser feito usando operadores new
/ delete
ou funções malloc
/ free
. Observe que essas funções funcionam de maneira semelhante, onde o usuário geralmente especifica o número de bytes a serem alocados e retorna o endereço onde a mesma quantidade de memória foi alocada. O programador pode, conseqüentemente, operar na região de memória fornecida, conforme necessário.
O próximo exemplo de código demonstra vários casos de alocação de diferentes objetos na memória heap. Um recurso importante do gerenciamento manual de memória é retornar a região de memória alocada ao sistema operacional quando ela não for mais necessária. A última operação é feita usando chamadas delete
/ free
correspondentes às suas contrapartes de alocação. Se o programa não liberar a memória desnecessária, há o risco de o sistema operacional ficar sem memória e, como resultado, o programa ser encerrado. Observe, porém, que o problema anterior ocorre principalmente em programas de longa execução, e eles são caracterizados como bugs de vazamento de memória.
#include <iostream>
using std::cout;
using std::endl;
int main() {
auto var4 = new int;
cout << var4 << endl;
int *arr2 = new int[4];
auto arr3 = new int[4];
cout << arr2 << endl;
cout << arr3 << endl;
delete var4;
delete[] arr2;
delete[] arr3;
return EXIT_SUCCESS;
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook