Rust高效内存优化库smallbox的使用,smallbox提供栈上存储小对象的轻量级容器实现

Rust高效内存优化库smallbox的使用

SmallBox是一个空间效率高的Box<T>替代方案,它会在栈上存储小值,对于大值则回退到堆分配。这种优化可以显著减少内存分配并提高处理许多小对象的应用程序性能。

快速开始

在你的Cargo.toml中添加SmallBox:

[dependencies]
smallbox = "0.8"

基本用法

use smallbox::SmallBox;
use smallbox::space::S4;

// 小值存储在栈上
let small: SmallBox<[u32; 2], S4> = SmallBox::new([1, 2]);
assert!(!small.is_heap());

// 大值会自动使用堆分配
let large: SmallBox<[u32; 32], S4> = SmallBox::new([0; 32]);
assert!(large.is_heap());

// 像常规Box一样使用
println!("Small: {:?}, Large: {:?}", *small, large.len());

完整示例代码

use smallbox::SmallBox;
use smallbox::space::*;

fn main() {
    // 使用S1空间(1字节)存储u8
    let tiny: SmallBox<u8, S1> = SmallBox::new(42);
    println!("Tiny value: {}, is_heap: {}", *tiny, tiny.is_heap());

    // 使用S4空间(4字节)存储小数组
    let small_array: SmallBox<[u8; 3], S4> = SmallBox::new([1, 2, 3]);
    println!("Small array: {:?}, is_heap: {}", *small_array, small_array.is_heap());

    // 使用S8空间(8字节)存储中等大小的结构体
    #[derive(Debug)]
    struct Point(f32, f32);
    let point: SmallBox<Point, S8> = SmallBox::new(Point(1.0, 2.0));
    println!("Point: {:?}, is_heap: {}", *point, point.is_heap());

    // 存储字符串切片
    let small_str: SmallBox<str, S16> = SmallBox::new("Hello, SmallBox!");
    println!("Small string: {}, is_heap: {}", &*small_str, small_str.is_heap());

    // 存储大对象会自动使用堆分配
    let big_array: SmallBox<[u8; 32], S16> = SmallBox::new([0u8; 32]);
    println!("Big array len: {}, is_heap: {}", big_array.len(), big_array.is_heap());

    // 使用动态trait对象
    let display: SmallBox<dyn std::fmt::Display, S8> = SmallBox::new(123);
    println!("Display: {}, is_heap: {}", &*display, display.is_heap());
}

性能基准

测试平台是AMD Ryzen 9 7950X3D 16核处理器上的Ubuntu 2204。

compare                             fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ box_large_item                   13.96 ns      │ 14.44 ns      │ 14.2 ns       │ 14.16 ns      │ 100     │ 12800
├─ box_small_item                   7.313 ns      │ 7.512 ns      │ 7.391 ns      │ 7.392 ns      │ 100     │ 25600
├─ smallbox_large_item_large_space  14.13 ns      │ 49.42 ns      │ 14.9 ns       │ 15.07 ns      │ 100     │ 12800
├─ smallbox_large_item_small_space  23.91 ns      │ 26.09 ns      │ 25 ns         │ 24.94 ns      │ 100     │ 6400
├─ smallbox_small_item_large_space  0.995 ns      │ 1.025 ns      │ 1.005 ns      │ 1.003 ns      │ 100     │ 102400
╰─ smallbox_small_item_small_space  0.985 ns      │ 1.015 ns      │ 0.995 ns      │ 0.996 ns      │ 100     │ 102400

许可证

根据以下任一许可证授权:

  • Apache License, Version 2.0
  • MIT License

任选其一。


1 回复

Rust高效内存优化库smallbox的使用

介绍

smallbox是一个Rust库,提供了在栈上存储小对象的轻量级容器实现。它主要用于优化内存分配,当对象足够小时直接在栈上存储,避免堆分配的开销;当对象较大时自动回退到堆分配。

这个库特别适合需要存储大量小对象的场景,可以显著减少内存分配次数和碎片化,提高性能。

主要特性

  • 栈上存储小对象,避免堆分配
  • 自动处理大小转换(小对象栈存储,大对象堆存储)
  • 零成本抽象(无运行时开销)
  • 支持DerefDerefMut,使用方便
  • 提供SmallBoxSmallOption两种容器

使用方法

基本使用

首先在Cargo.toml中添加依赖:

[dependencies]
smallbox = "0.8"

示例1:基本存储

use smallbox::SmallBox;
use smallbox::space::S4;

// S4表示栈空间为4个机器字(32位系统是16字节,64位系统是32字节)
let small: SmallBox<_, S4> = SmallBox::new([1u32, 2, 3, 4]);
assert!(!small.is_heap());

// 超过栈容量会自动转为堆存储
let large: SmallBox<_, S4> = SmallBox::new([1u32; 8]);
assert!(large.is_heap());

示例2:使用枚举空间

use smallbox::SmallBox;
use smallbox::space::*;

// 使用S1(1个字)到S64(64个字)的空间
let tiny: SmallBox<u8, S1> = SmallBox::new(42);
let small: SmallBox<String, S4> = SmallBox::new("hello".to_string());
let medium: SmallBox<Vec<u8>, S16> = SmallBox::new(vec![0; 128]);

示例3:SmallOption

use smallbox::SmallOption;
use smallbox::space::S2;

let mut opt: SmallOption<Box<dyn std::fmt::Debug>, S2> = SmallOption::empty();
assert!(opt.is_none());

opt.insert(Box::new(42));
assert!(opt.is_some());

opt.take();
assert!(opt.is_none());

示例4:自定义类型

use smallbox::SmallBox;
use smallbox::space::S8;

struct Point {
    x: f64,
    y: f64,
    z: f64,
}

let point = Point { x: 1.0, y: 2.0, z: 3.0 };
let small_point: SmallBox<Point, S8> = SmallBox::new(point);
println!("Point: ({}, {}, {})", small_point.x, small_point.y, small_point.z);

完整示例demo

use smallbox::{SmallBox, SmallOption};
use smallbox::space::{S2, S4, S8};

fn main() {
    // 示例1:基本存储
    example_basic_storage();
    
    // 示例2:使用枚举空间
    example_enum_space();
    
    // 示例3:SmallOption
    example_small_option();
    
    // 示例4:自定义类型
    example_custom_type();
}

fn example_basic_storage() {
    println!("=== 示例1:基本存储 ===");
    
    // 使用S4空间(4个机器字)
    let small: SmallBox<[u32; 4], S4> = SmallBox::new([1, 2, 3, 4]);
    println!("小数组存储在栈上: {}", !small.is_heap());
    
    let large: SmallBox<[u32; 8], S4> = SmallBox::new([1; 8]);
    println!("大数组存储在堆上: {}", large.is_heap());
}

fn example_enum_space() {
    println!("\n=== 示例2:使用枚举空间 ===");
    
    // 使用不同大小的空间
    let tiny: SmallBox<u8, S2> = SmallBox::new(42);
    println!("u8存储在栈上: {}", !tiny.is_heap());
    
    let small: SmallBox<String, S4> = SmallBox::new("hello".to_string());
    println!("String存储在堆上: {}", small.is_heap());
}

fn example_small_option() {
    println!("\n=== 示例3:SmallOption ===");
    
    let mut opt: SmallOption<Box<dyn std::fmt::Debug>, S2> = SmallOption::empty();
    println!("初始状态为空: {}", opt.is_none());
    
    opt.insert(Box::new("Rust"));
    println!("插入值后: {}", opt.is_some());
    
    opt.take();
    println!("取出值后: {}", opt.is_none());
}

fn example_custom_type() {
    println!("\n=== 示例4:自定义类型 ===");
    
    #[derive(Debug)]
    struct User {
        id: u64,
        name: String,
        active: bool,
    }
    
    let user = User {
        id: 1,
        name: "Alice".to_string(),
        active: true,
    };
    
    // 使用S8空间(8个机器字)
    let small_user: SmallBox<User, S8> = SmallBox::new(user);
    println!("用户信息: {:?}", small_user);
}

性能建议

  1. 根据常见对象大小选择合适的空间大小
  2. 对小对象频繁创建销毁的场景特别有效
  3. 对于始终大于栈空间的对象,直接使用Box可能更高效
  4. 可以通过is_heap()检查是否使用了堆分配来优化使用模式

注意事项

  • 栈空间大小是编译时确定的
  • 对象大小超过栈空间时会自动转为堆存储
  • 移动SmallBox是廉价的,因为它只复制指针(对于堆存储的情况)

smallbox为Rust程序提供了灵活高效的内存优化方案,特别适合需要处理大量小对象或不确定对象大小的场景。

回到顶部