嵌入式中的Vec等容器使用
由于Rust嵌入式中大多是no_std环境,于是标准库中很多函数不能使用,比如Vec等,但是很多人会觉得这样写Rust太麻烦了,这里介绍两种方案可以解决:
- 使用heapless
- 使用全局的allocator
heapless
heapless是Rust嵌入式生态中的重要库,专为资源受限环境设计的静态数据结构集合。它提供了与标准库类似的容器(如Vec、String等),但完全不依赖堆内存分配,所有内存都在编译时分配在栈上或静态区域。使用时需要通过类型参数指定最大容量,虽然容量固定无法动态扩展,但这种设计确保了内存使用的可预测性,避免了嵌入式系统中常见的内存碎片和分配失败问题,特别适合实时系统和无操作系统环境。 类似这样:
#![allow(unused)] fn main() { use heapless::Vec; let mut vec = Vec::<u8, 10>::new(); vec.push(1).unwrap(); vec.push(2).unwrap(); println!("{:?}", vec); }
使用全局的allocator
嵌入式中推荐使用embedded-alloc 用法非常简单
#![no_std] #![no_main] extern crate alloc; use cortex_m_rt::entry; use embedded_alloc::LlffHeap as Heap; #[global_allocator] static HEAP: Heap = Heap::empty(); #[entry] fn main() -> ! { // Initialize the allocator BEFORE you use it { use core::mem::MaybeUninit; const HEAP_SIZE: usize = 1024; static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) } } // now the allocator is ready types like Box, Vec can be used. loop { /* .. */ } }
简而言之就是创建了一个全局的allocator,能实现malloc、free、realloc等操作,这样我们就能使用需要动态内存分配的Vec、Box等容器了。也可以自己做一个实现了 GlobalAlloc trait的内存池
embedded-alloc的使用需要critical section的支持,所以Cargo.toml需要在cortex-m中启用
cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]}
注意:嵌入式系统中使用动态内存分配需要注意内存碎片和内存不足(OOM)等问题,因此需要谨慎使用或进行充分测试。