Utilize Stack vs Heap Memory Allocation em C++

Jinku Hu 12 outubro 2023
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;
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

Artigo relacionado - C++ Memory