5 unstable releases

0.3.0 Nov 22, 2024
0.2.0 Nov 13, 2024
0.1.2 Aug 12, 2024
0.1.1 Dec 25, 2023
0.1.0 Aug 22, 2023

#317 in Memory management

Download history 21/week @ 2024-08-16 4/week @ 2024-08-23 5/week @ 2024-08-30 15/week @ 2024-09-13 16/week @ 2024-09-20 12/week @ 2024-09-27 3/week @ 2024-10-04 3/week @ 2024-10-11 2/week @ 2024-10-18 1/week @ 2024-10-25 3/week @ 2024-11-01 103/week @ 2024-11-08 44/week @ 2024-11-15 168/week @ 2024-11-22 16/week @ 2024-11-29

331 downloads per month
Used in 2 crates

MIT/Apache

91KB
2.5K SLoC

hipool

内存池提供高效的内存分配策略。适合于基于生命周期进行内存管理的业务场景.

内存池只有内存的分配接口,没有释放接口,所有内存都在内存池生命周期结束的时候统一释放.

C/C++中内存池至少存在以下两个挑战:

  1. 如何保证内存池分配的内存不会在内存池销毁后还在使用? 引用计数机制可以解决,但增大开销,降低收益.
  2. 如何保证内存池只在单线程下使用?增加并发保护,但增大开销,降低收益.

以上两个问题在RUST中可以在编译期间解决,安全又高效。

  1. 基于生命周期管理机制,可以保证内存池生命期一定大于其分配的内存的生命期.
  2. 内存池不支持Sync,限定只在单线程下使用.

版本变更说明

  1. 0.3.0

GenricAlloc/Boxed/Arc/Rc的分配接口变化,消除MaybeUninit,从接口上保证安全性. Arc/Rc接口变化,新增从Boxed构建.


lib.rs:

提供内存池管理机制, 支持从堆上动态分配,或者事先分配的一块内存空间,可能在堆上也可能在栈上.

Examples

简单类型,直接传递初始值,会有一次拷贝

use hipool::{ MemPool, Boxed};
let pool = MemPool::new(0);
let psize = Boxed::new_in(&pool, 100).unwrap();
assert_eq!(*psize, 100);

复杂类型,构造过程中还会涉及动态申请内存.

use core::ptr;
use hipool::{ MemPool, Boxed};

let pool = MemPool::new(0);
struct Foo<'a> {
    val: Boxed<'a, i32, MemPool>,
}
let foo = Boxed::new_then_in(&pool, || {
    Ok(Foo {
        val: Boxed::new_in(&pool, 100)?,
    })
}).unwrap();
assert_eq!(*foo.val, 100);

// 也可以如下申请,两种申请方式,在内存池中内存的申请顺序不同
let val = Boxed::new_in(&pool, 99).unwrap();
let foo = Boxed::new_in(&pool, Foo { val }).unwrap();
assert_eq!(*foo.val, 99);

有时候需要在栈上分配数据,需要把栈空间适配为Pool接口,则可使用BufPool完成适配

use hipool::{ BufPool, Boxed};
let mut buf = [0_u8; 100];
let mut pool = BufPool::new(&mut buf);
let psize = Boxed::new_in(&pool, 100).unwrap();
assert_eq!(*psize, 100);

有时候分配的Pool也需要在堆上,可以用另外的构造方式,如下:

use hipool::{ MemPool, Boxed };

let mut pool = MemPool::new_boxed(0).unwrap();
let int_array = Boxed::new_slice_then_in(&*pool, 100, |_| {
    Ok(0)
}).unwrap();
int_array.iter().for_each(|n| assert_eq!(*n, 0));

更多的调用接口

use hipool::{ MemPool, Boxed };
use core::alloc::Layout;

let pool = MemPool::new_boxed(0).unwrap();

let val = Boxed::new_in(&*pool, 1).unwrap();
assert_eq!(*val, 1);

let val = Boxed::new_then_in(&*pool, || {
    Ok(100)
}).unwrap();
assert_eq!(*val, 100);

let ivals = [0, 1, 2, 3];
let vals = Boxed::uninit_slice_in::<i32>(&*pool, ivals.len()).unwrap();
let vals = vals.write_slice_then(|n| {Ok(ivals[n])}).unwrap();
assert_eq!(vals[0], 0);
assert_eq!(vals[1], 1);
assert_eq!(vals[2], 2);
assert_eq!(vals[3], 3);

let vals = unsafe { Boxed::new_buf_in(&*pool,
Layout::array::<i32>(2).unwrap()).unwrap().cast_slice::<i32>(2) };
vals.iter().for_each(|val| println!(" {:?} ", val));

let vals = Boxed::new_slice_then_in(&*pool, 2, |n| {
    Ok(n as i32)
}).unwrap();
assert_eq!(vals[0], 0);
assert_eq!(vals[1], 1);

Dependencies

~29KB