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