#stack #slice #memory-allocator #heap-allocator

second-stack

为短生命周期切片和大型值提供快速分配器

8个版本

0.3.5 2022年7月14日
0.3.4 2022年6月27日
0.2.1 2019年9月21日
0.2.0 2019年6月16日

内存管理 中排名第 95

Download history 19/week @ 2024-04-02 1/week @ 2024-04-09 43/week @ 2024-04-16 57/week @ 2024-04-23 724/week @ 2024-04-30 731/week @ 2024-05-07 1441/week @ 2024-05-14 1498/week @ 2024-05-21 1978/week @ 2024-05-28 2054/week @ 2024-06-04 1779/week @ 2024-06-11 822/week @ 2024-06-18 1032/week @ 2024-06-25 814/week @ 2024-07-02 1294/week @ 2024-07-09 841/week @ 2024-07-16

每月下载量 4,147
用于 15 个crates(直接使用2个)

MIT 许可证

17KB
237

线程的栈是管理内存的高性能方式。但是,它不能用于大型或动态大小的分配。如果线程有一个适合该目的的第二栈会怎么样呢?

是的,我们有一个。那么第二个栈呢?...Pippin,可能。

second-stack 是短生命周期、可能大型值和切片的分配器。与大多数时候使用堆相比,使用线程的栈比使用 Vec 更快,原因也相同。

内部表示是一个线程局部栈,按需增长。一旦容量饱和,相同的分配将被许多消费者重复使用,这使得它更有效率,因为更多库采用它。

second-stack 最初是为了在WebGL中编写动态缓冲区而开发的(例如:程序生成一些三角形/颜色,将它们写入缓冲区,并在每一帧多次将它们传递给图形卡,而不会产生许多堆分配的成本)。但是,随着时间的推移,我发现需要短生命周期切片很常见,而使用 second-stack 可以在各个地方实现最佳内存重用和性能。

使用此API有两种方法。首选方法是使用委托给共享线程局部的方法(如 bufferuninit_slice)。使用这些方法可以确保多个库高效地重用分配,而不必传递上下文并在其公共API中暴露此实现细节。或者,如果您需要更多控制,您可以使用 Stack::new() 创建自己的管理堆栈。

使用 buffer 的示例

// Buffer fully consumes an iterator,
// writes each item to a slice on the second stack,
// and gives you mutable access to the slice.
// This API supports Drop.
buffer(0..1000, |items| {
    assert_eq!(items.len(), 1000);
    assert_eq!(items[19], 19);
})

使用 uninit_slice 的示例

uninit_slice(100, |slice| {
    // Write to the 100 element slice here
})

使用 Stack 的示例

let stack = Stack::new();
stack.buffer(std::iter::repeat(5).take(100), |slice| {
    // Same as second_stack::buffer, but uses an
    // owned stack instead of the threadlocal one.
    // Not recommended unless you have a specific reason
    // because this limits passive sharing.
})

放置巨大值的示例

struct Huge {
    bytes: [u8; 4194304]
}

uninit::<Huge>(|huge| {
    // Do something with this very large
    // value that would cause a stack overflow if
    // we had used the thread stack
});

常见问题解答

这与类似 bumpalo 的跳增分配器有何不同?

像 bumpalo 这样的跳增分配器是针对 面向阶段 的分配而设计的区域分配器,而 second-stack 是一个栈。

这允许 second-stack

  • 支持 Drop
  • 根据需要动态增加分配大小,而不是要求预先知道大小
  • 更早地释放和重用内存
  • 方便地支持“大局部变量”,无需对程序进行架构设计以适应区域模型

无运行时依赖