Quanto é demais o uso da pilha?

22

Ultimamente, quando eu estiver escrevendo C ou C ++, declararei todas as minhas variáveis ​​na pilha apenas porque é uma opção, ao contrário do Java.

No entanto, ouvi dizer que é uma má idéia declarar coisas grandes na pilha.

  1. Por que exatamente é esse o caso? Eu acho que o estouro de pilha está envolvido, mas não sei muito bem por que isso acontece.
  2. Quanta coisa na pilha é demais?

Não estou tentando colocar arquivos de 100 MB na pilha, apenas uma dúzia de matrizes de kilobytes para usar como buffers de string ou qualquer outra coisa. Isso é muito uso de pilha?

(Desculpe, se duplicado, a busca por pilha continuava fornecendo referências ao estouro de pilha. Não há nem uma etiqueta de pilha de chamada, apenas usei a abstrata.)

Elliot Way
fonte
1
Como você "coloca arquivos de 100 MB na pilha"? As implementações de buffer e contêiner (e similares como std :: string) geralmente usam o heap para armazenar sua carga útil.
21716 Murphy
2
Você pode usar uma quantidade razoável de uso da pilha por função / método até que a recursão esteja envolvida; então, você corre o risco de limitar severamente seus recursos, em relação à profundidade recursiva, portanto, nas funções recursivas, você deseja usar o mínimo de recursos locais. variável / espaço de pilha possível.
Erik Eidt 21/02
3
Observe que C e C ++ são diferentes. Uma std::vector<int>variável local não ocupa muito espaço na pilha, a maioria dos dados está no heap.
Basile Starynkevitch 21/02

Respostas:

18

Depende do seu sistema operacional. No Windows, o tamanho máximo típico para uma pilha é de 1 MB, enquanto é de 8 MB em um Linux moderno típico, embora esses valores sejam ajustáveis ​​de várias maneiras. Se a soma de suas variáveis ​​de pilha (incluindo despesas gerais de baixo nível, como endereços de retorno, argumentos baseados em pilha, espaços reservados para valores de retorno e bytes de alinhamento) em toda a pilha de chamadas exceder esse limite, você obterá um estouro de pilha, o que normalmente reduz o seu programa sem nenhuma chance de recuperação.

Alguns kilobytes geralmente são bons. Dezenas de kilobytes são perigosos porque começam a resumir. Centenas de kilobytes é uma péssima idéia.

Sebastian Redl
fonte
1
A pilha típica não limita vários megabytes (ou seja, geralmente mais de um, mas provavelmente menos de uma dúzia) hoje em 2016? No meu desktop Linux, é 8Mbytes por padrão ...
Basile Starynkevitch
"No Linux, o tamanho máximo típico para uma pilha é de 1 MB" $ ulimit -ano meu sistema retorna entre outros stack size (kbytes, -s) 8192.
Murphy
9

A única resposta válida é vaga: "é demais quando a pilha transborda".

A menos que você tenha controle total sobre a implementação de todas as linhas de código entre o ponto de entrada do programa e a função em questão, não será possível fazer suposições sobre a quantidade de pilha disponível. Você não pode, por exemplo, garantir que a chamada dessa função nunca cause um estouro de pilha:

void break_the_camels_back()
{
    int straw;
    ...
}

A pilha padrão de 8 MiB nos Unixes modernos tem bastante espaço para as pilhas, especialmente para alguém como eu, que é um velhote suficiente para se lembrar de CPUs com ponteiros de pilha de 8 bits. A realidade prática é que é improvável que você exploda isso sem tentar. Se o fizer, exceder o limite da pilha é geralmente considerado uma violação de segmentação, e sistemas com gerenciamento de memória suficiente para detectá-lo enviarão um SIGSEGVquando isso acontecer.

Você tem algumas opções. Primeiro é não adivinhar quanta pilha está disponível e perguntar ao sistema. Qualquer coisa em conformidade com o POSIX terá uma getrlimit(2)função que informará o limite superior. RLIMIT_STACKé o limite específico que você deseja. O segundo é monitorar a quantidade de pilha que seus programas estão usando e tomar decisões sobre variáveis ​​automáticas versus alocação dinâmica de memória com base nisso. Até onde eu sei, não existem funções padrão para determinar quanto da pilha é usada, mas programas como o valgrindpodem analisar por você.

Blrfl
fonte
4

Se você alocar uma matriz de, digamos, 10.000 bytes na pilha, essa matriz é limitada em tamanho. 10.000 podem ser muito, mas se você precisar de 10.001 bytes, seu programa poderá falhar ou algo pior. Portanto, nessa situação, você deseja algo que se adapte ao tamanho necessário e que não esteja na pilha.

Matrizes de tamanho fixo para buffers de seqüência de caracteres na pilha não são um problema porque mantêm memória na pilha, são um problema porque os buffers de tamanho fixo são um problema fatal que está esperando para acontecer.

Mas se você usa C ++ e declara, por exemplo, um std :: string ou um std :: vec na pilha, o que está na pilha será realmente de tamanho fixo e pequeno. Os dados reais serão armazenados na pilha. Você pode armazenar um milhão de caracteres em uma instância std :: string, e apenas uma quantidade muito pequena de dados (geralmente de 8 a 24 bytes, dependendo da implementação) na pilha e um milhão de bytes no heap.

gnasher729
fonte
2

Bem, 1 MB é uma boa estimativa para * nix. A recursão pode ser um dos principais motivos para o estouro de pilha em combinação com as alocações de pilha. No entanto, na maioria dos casos, os objetos god que parecem superficialmente grandes demais para serem colocados na pilha são projetados bem para gerenciar sua memória interna na pilha e usar a pilha apenas como uma maneira de ser destruída automaticamente quando a pilha é exibida. O destruidor liberará os enormes pedaços de memória gerenciados internamente. Os contêineres std são projetados dessa maneira e os ponteiros compartilhados / exclusivos também.

O importante é não alocar grandes pedaços de mem bruto na pilha como char [1024 * 1024] e projetar classes para agrupar alocações de heap e usar a pilha apenas para a conveniência de chamar automaticamente o destruidor.

Asterisco
fonte