Existe uma desvantagem em alocar uma enorme quantidade da pilha para uma única matriz em um sistema incorporado?

12

Normalmente, não tenho problemas para decidir se alguns dados devem ser globais, estáticos ou na pilha (sem alocação dinâmica aqui, portanto, sem uso da pilha). Também li algumas perguntas e respostas como essa, mas minha pergunta é mais específica, pois envolve uma enorme quantidade de dados, enorme em comparação com a memória do sistema.

Estou trabalhando com um código existente que tento melhorar (design, possíveis problemas, performances etc.). Esse código é executado em um antigo MCU de 8 bits com apenas 4KB de RAM . Neste código, enfrento o uso de uma matriz de quase 1 KB (sim, 1 KB em um sistema de RAM de 4KB ). Cada byte dessa matriz é usado, essa não é a questão. O problema é que essa matriz é uma matriz estática no arquivo em que foi declarada, portanto seu ciclo de vida é o mesmo do programa (ou seja, pode ser considerado infinito).

No entanto, depois de ler o código, acabei de descobrir que esse array não precisa de um ciclo de vida infinito; ele é construído e tratado de maneira totalmente processual; portanto, devemos poder declará-lo apenas na função em que é usado, dessa forma, ele estaria na pilha e, portanto, salvaríamos esse 1 KB de RAM.

Agora a pergunta: seria uma boa ideia? Do ponto de vista do design, se não precisar de um ciclo de vida infinito / global, ele pertence à pilha. Mas ei, isso é 1KB de 4KB, não há nenhuma desvantagem em alocar 25% da RAM assim? (que pode ser 50% ou mais da pilha)

Alguém poderia compartilhar alguma experiência com esse tipo de situação ou alguém pensa em algum motivo válido para não colocar essa matriz na pilha? Estou procurando desvantagens técnicas e comentários sobre o design.

A única coisa que tenho consciência é que tenho que ter certeza de que tenho 1 KB de pilha livre ao entrar nessa função. Talvez seja tudo o que tenho para resolver, talvez não.

Tim
fonte
4
Você escreveu "e, portanto, salve esse 1 KB de RAM". Guarde para quê? Esse 1 KB deve estar disponível quando você precisar para a matriz. Por que não fazer uma alocação estática? Você tem outro uso para a memória quando ela não é necessária para a matriz?
Kkrambo # 11/16
@kkrambo Em algum momento, consideramos que um sistema está cheio quando não podemos adicionar mais nada à RAM, seja estática ou na pilha. Se colocarmos essa matriz na pilha apenas quando a usarmos, ela deixará lugar para outra funcionalidade, desde que não sejam usadas ao mesmo tempo. Mas a questão é totalmente legítimo, no momento, se não mudar nada no SW, nós não precisamos de mais memória RAM;)
Tim
1
Você poderia esclarecer se essa matriz tem conteúdo que sempre permanece o mesmo ou se muda quando a função que a utiliza é invocada?
Blrfl
@Blrfl Muda sempre que a função é chamada.
Tim

Respostas:

8

A única coisa que tenho consciência é que tenho que ter certeza de que tenho 1 KB de pilha livre ao entrar nessa função.

Sim, e isso é uma forte restrição. É melhor ter certeza estaticamente do que ter um espaço tão grande disponível na pilha. Se o código for pequeno, se você estiver usando um GCC recente para compilar seu código, consulte isso .

BTW, alguns microprocessadores baratos podem usar um quadro de chamada "grande" mais caro que um "normal" (por exemplo, porque o conjunto de instruções favoreceria um deslocamento de um byte do ponteiro da pilha). YMMV.

Além disso, se você estiver codificando em C e se achar que seu grande array pode ter seu espaço reutilizado para outros fins, considere torná-lo um membro da união (com uma variável global de union tipo). Sim, isso é muito feio.

Como alternativa, você pode considerar a codificação de um alocador de heap primitivo adequado ao seu aplicativo (e ele pode ter uma API diferente de malloc& free....).

Basile Starynkevitch
fonte
1
Obrigado, eu estava realmente esperando esse tipo de resposta, ou seja, mantenha-o estaticamente alocado para garantir que eu não acabe com um estouro de pilha. Infelizmente não tenho um compilador recente do GCC e o código não é pequeno.
Tim
Você não consegue (talvez compilando o GCC a partir do código-fonte) um compilador GCC para sua plataforma?
Basile Starynkevitch 11/11
2
Eu já tenho um, é realmente muito antigo. Trabalhar em um novo não está no meu escopo, nem caberia na minha agenda. Mas claro, algumas coisas seriam mais fáceis com as ferramentas atualizadas.
Tim
3
Pedir ao seu chefe que obtenha um GCC mais novo (fornecendo ferramentas binárias atualizadas ou dando tempo para a recompilação do GCC) vale a pena IMHO, porque provavelmente o GCC mais novo otimizaria um pouco melhor (você sabe gcc -flto -Os? ) e você pode ganhar um pouco de memória ....
Basile Starynkevitch
2
Está no caminho certo, mas isso não acontecerá daqui a pouco. Eu já uso -Os em outros sistemas com cadeias de ferramentas mais recentes, mas não estava ciente desse parâmetro -flto, obrigado por apontá-lo. (Observe que eu fiz alguns testes com o GCC -Os e -O1-3 há algumas semanas no GCC 5.4.1 e a RAM era a mesma o tempo todo. O tempo de execução do FLASH e do MCU era diferente. Isso não estava no mesmo MCU que eu mencionei neste Q / A)
Tim
6

As pessoas tendem a ser cautelosas com uma pilha grande, porque ela cresce na RAM e sobrescreve os valores das variáveis, levando a um comportamento inexplicável. Isso fica ainda pior, porque você precisa conhecer o menor endereço possível do ponteiro da pilha e subtrair o tamanho a ser alocado ao entrar na rotina.

Tudo isso é um trabalho para o gerenciamento de memória de hardware (deve gerar traps ou falhas quando ocorre um estouro de pilha) ou para o compilador, pois possui recursos para esse tipo de análise.

Caso contrário, você pode fazer o que quiser com sua RAM.

Martin Sugioarto
fonte
4

Como as respostas anteriores apontaram, também recomendo deixar a matriz estática se ela se encaixar na memória. Na maioria dos casos, é muito mais importante ter uma pegada determinística na memória, mesmo que isso signifique que você "desperdiça" memória para variáveis ​​que não são usadas o tempo todo. Colocar matrizes grandes em sua pilha é muito fácil de explodir, e os estouros de pilha tendem a causar problemas difíceis de encontrar e de reproduzir (se você não pode usar o MMU para proteger a pilha).

A sugestão de compartilhar o bloco com outros dados com a união é válida para IMO, embora também possa ser fonte de problemas difíceis de encontrar, se você localizar variáveis ​​erradas nele.

Se você estiver ficando sem memória e precisar desesperadamente criar variáveis ​​de vida mais curta para compartilhá-la, antes de mover a matriz para a pilha, consideraria adicionar alocação dinâmica de memória, mesmo que ela tenha suas próprias desvantagens. Nesse caso, pode não ser uma resposta, pois o array parece bastante grande comparado à memória disponível.

MaKo
fonte
1

Você tem outra opção se tiver algum tipo de armazenamento flash. Você pode trocar a velocidade de acesso por memória RAM armazenando seus dados em flash e lendo e pesquisando lá. Você só precisaria carregar um registro de cada vez no ram. Será um pouco mais complicado se você precisar atualizar os registros. Você precisará de um mecanismo segmentado e nivelado ao desgaste. Eu fiz isso no passado e incluí um índice para acelerar o acesso.

Tereus Scott
fonte
1
Eu também já fiz isso no passado, mas minha pergunta era mais sobre os problemas que eu poderia enfrentar se eu colocasse isso na pilha, não sobre as alternativas à RAM quando estamos com falta dela. Obrigado por responder de qualquer maneira
Tim
1

Especialmente ao trabalhar com sistemas embarcados, você deseja que o máximo possível de falhas ocorra no momento da compilação e nada falhe em tempo de execução (bom, se conseguirmos isso, no entanto ...).

A criação de grandes matrizes que você pode precisar em estados arbitrários do seu programa alocado estaticamente faz exatamente isso - o vinculador acabará alertando você "isso não se encaixa na RAM", enquanto a alocação da pilha simplesmente faria o seu programa travar com uma pilha difícil de depurar transborda.

tofro
fonte