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
每月下载量 4,147
用于 15 个crates(直接使用2个)
17KB
237 行
线程的栈是管理内存的高性能方式。但是,它不能用于大型或动态大小的分配。如果线程有一个适合该目的的第二栈会怎么样呢?
是的,我们有一个。那么第二个栈呢?...Pippin,可能。
second-stack
是短生命周期、可能大型值和切片的分配器。与大多数时候使用堆相比,使用线程的栈比使用 Vec
更快,原因也相同。
内部表示是一个线程局部栈,按需增长。一旦容量饱和,相同的分配将被许多消费者重复使用,这使得它更有效率,因为更多库采用它。
second-stack
最初是为了在WebGL中编写动态缓冲区而开发的(例如:程序生成一些三角形/颜色,将它们写入缓冲区,并在每一帧多次将它们传递给图形卡,而不会产生许多堆分配的成本)。但是,随着时间的推移,我发现需要短生命周期切片很常见,而使用 second-stack
可以在各个地方实现最佳内存重用和性能。
使用此API有两种方法。首选方法是使用委托给共享线程局部的方法(如 buffer
和 uninit_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
- 根据需要动态增加分配大小,而不是要求预先知道大小
- 更早地释放和重用内存
- 方便地支持“大局部变量”,无需对程序进行架构设计以适应区域模型