Compilou e Funcionou! Então Está Correto! Hora de Dar Merge e Seguir para a Próxima Tarefa?

Recentemente, publiquei no GitHub a versão desktop de um emulador CHIP-8 que escrevi em Rust GitHub. Ao portar esse emulador para o ESP32, me deparei com um problema de gerenciamento de memória. No ambiente desktop, a stack geralmente tem espaço suficiente para armazenar arrays grandes, mas no ESP32, essa abordagem pode causar problemas. A solução? Mover esses dados para a heap usando Box. Neste post, vou mostrar como às vezes a gente escreve um código que funciona, mas depois percebe que ele precisa de ajustes para rodar melhor no ambiente certo.

O Problema: Stack Pequena no ESP32

O ESP32 tem uma stack limitada (às vezes apenas 8 KB por thread). No meu caso, eu armazenava a representação da tela do emulador como um array fixo de 2048 bools:

fn opcode_00e0(&mut self) {
    self.screen = [false; SCREEN_WIDTH * SCREEN_HEIGHT];
}

Essa foi a minha primeira abordagem, pois como era minha primeira tentativa com emuladores, foquei em um código funcional antes de pensar em otimizações. No desktop, essa abordagem funcionava bem, mas em um microcontrolador, pode resultar em stack overflow. Isso acontece porque esse array de 2048 elementos ocupa 2048 bytes diretamente na stack, o que é um uso significativo para um sistema embarcado.

A Solução: Alocar na Heap com Box

Para evitar esse problema, podemos mover o array para a heap, que tem mais espaço disponível. Em Rust, usamos Box para isso:

fn opcode_00e0(&mut self) {
    self.screen = Box::new([false; SCREEN_WIDTH * SCREEN_HEIGHT]);
}

Aqui, Box::new(...) aloca o array na heap e retorna um ponteiro seguro para ele. Isso reduz a pressão na stack e permite que o ESP32 gerencie a memória de forma mais eficiente.

Comparando Uso de Memória

Para visualizar a diferença, podemos medir o tamanho dessas estruturas na stack:

use core::mem::size_of;
println!("Tamanho do array na stack: {} bytes", size_of::<[bool; 2048]>());
println!("Tamanho do Box na stack: {} bytes", size_of::<Box<[bool; 2048]>>());

O array ocupa 2048 bytes na stack, enquanto Box<[bool; 2048]> ocupa apenas 8 bytes (um ponteiro para a heap).

Conclusão

Mover grandes estruturas de dados para a heap é uma estratégia essencial ao trabalhar com Rust no ESP32. Isso evita estouros de stack e melhora a estabilidade do código.

Esse exemplo também mostra um aprendizado importante: muitas vezes, o primeiro código que escrevemos funciona, mas não está correto ou otimizado para o contexto em que será executado. Com o tempo e a experiência, identificamos melhorias necessárias para tornar o código mais eficiente e adequado ao hardware

Ainda vou começar a publicar o emulador com as novas modificações no GitHub, pois ainda existem vários pontos que cabem otimizações. Se você tem experiência com Rust e sistemas embarcados, compartilhe nos comentários suas abordagens para lidar com memória limitada! 🚀

🔗 Confira o código no GitHub.

🔗 Link para a postagem no Linkedin