🧠 Memory Management in FluxSand

This document describes the memory usage strategy and how safe, efficient memory management was implemented throughout the FluxSand project. The focus is on avoiding leaks, minimizing overhead, and adhering to best practices in modern C++ for embedded systems.


🔒 Encapsulation and RAII Principles

All memory in the system is managed using stack allocation or Resource Acquisition Is Initialization (RAII) style wrappers.

  • No raw new/delete used in application code
  • All class members use value types or smart references
  • Ownership is clear and confined to the constructors and destructors

Example:

class Gpio {
  // Chip and line pointers are acquired once, released in ~Gpio
  gpiod_chip* chip_;
  gpiod_line* line_;
};

🧼 Ensures all resources (file descriptors, hardware handles) are cleaned up even if an exception occurs.


🧵 Thread-Safe Resource Lifetimes

Each thread in FluxSand is responsible for its own lifecycle and cleanup.

  • Threads such as InferenceTask, ThreadTask, and CalibrateThreadTask are joined on destruction
  • No dangling references or race conditions due to premature deallocation
  • std::binary_semaphore and message-passing used instead of shared raw pointers

📊 Memory Footprint Control

FluxSand is designed to run on Raspberry Pi 5 with limited memory. Strategies to minimize memory use:

  • No dynamic STL containers with uncontrolled growth
  • Bounded history buffers (std::deque<float> with fixed size)
  • std::array used over std::vector where applicable
  • ONNX model preloaded into memory only once and reused

Example:

std::deque<ModelOutput> prediction_history_; // bounded in size

🚫 Common Pitfalls Avoided

Anti-Pattern What We Used Instead
Manual new / delete Stack objects and RAII
Global mutable state Private members with clear ownership
Leaky loops or buffers Fixed-size containers, bounds checking
Unsafe memory reuse Stateless callbacks and message passing

✅ Summary

FluxSand achieves memory safety and efficiency by:

  • Using RAII and encapsulated class ownership
  • Ensuring thread lifecycles match resource scope
  • Avoiding leaks, dangling references, or over-allocation
  • Using predictable data structures with bounded memory usage

This results in a robust system that runs reliably on embedded hardware without the risk of fragmentation or unpredictable memory growth.

For profiling results or heap usage statistics, see the “Assessment” section.