17个版本 (破坏性)
0.14.0 | 2022年9月13日 |
---|---|
0.12.0 | 2022年9月2日 |
0.6.0 | 2022年7月31日 |
#337 in 内存管理
每月下载量43
98KB
2.5K SLoC
描述
Onsen提供热池对象。在大多数情况下,从这样的池进行分配比标准分配器更快,并且提供了更好的局部性。对于小型到中型对象,性能提升约为20%或更好。对于大型对象,由于缓存效果趋于平衡,收益会减小。这些改进涵盖了由于局部性操作对象,而不仅仅是加快分配速度。
详情
Onsen池以指数级增长的大小分配块。分配从这些块中提供服务。释放的条目被保留在双链循环空闲列表中。这个空闲列表被弱有序地保持,并且入口点始终指向上次操作发生的地方,以保持缓存热。
Box, Rc 和 Sc
Onsen附带自己的Box
和Rc
/Weak
实现,它们以安全的方式包装底层的RcPool
。还提供了一种不支持的弱引用的Sc
引用计数框,它为小对象提供了优势,因为弱引用会增加一些重量。
对于这些中的每一个,还有一个使用静态全局池的变体。
插槽
从池分配返回Slot
处理程序。这些是轻量级的内存地址抽象,它们不保留与它们分配的池的关系。这种设计背后的原理是使它们在使用NaN标记的VM中可用。
插槽策略
插槽由类型状态策略保护,这可以在编译时防止一些错误使用。
插槽和安全
因此,需要小心处理插槽,并需要执行某些合同。该库提供了一些帮助以确保正确性。有些事情无法断言,并由不安全函数保护。高级API(如上述的Box
、Rc
和Sc
)可以轻松以安全的方式执行这些操作。
- 插槽必须返回给原始池。
- 插槽的寿命不能超过它们分配的池。
- 当池在仍有活动分配的情况下被丢弃时,在调试模式下将引发恐慌。
- 当一个包含活动分配的池在发布模式下被丢弃时,它会泄漏其内存。这是不幸的,但确保了程序的安全。
- 存在一个
pool.leak()
函数,在丢弃池的同时泄漏其内存块。当不再尝试从该池中释放内存时,可以使用此功能。 - 这同样适用于u64 NaN标签。
- 槽位必须只释放一次。
- 这始终是断言的。但断言可能在槽位再次分配时失败。
- 槽位不是'拷贝'的,因此不能安全地两次释放槽位。但是,引用计数实现和NaN标记功能使用显式的'copy()'函数,可以复制'u64'并尝试多次释放。这些函数因为这一点是'不安全的'。
- 从槽位获得的引用不能比释放
Slot
的时间长。- 这是使
Slot
释放函数不安全的主要原因。池无法知道引用是否仍在使用。应该提供或使用安全的抽象来强制执行这一点。
- 这是使
功能
Onsen提供了单线程的Pool
、单线程引用计数的RcPool
和多线程的TPool
。其他功能受功能标志的控制。
- parking_lot 在
TPool
中使用parking_lot(而不是std::sync::Mutex
)。当已经使用parking_lot时,这很有意义。在Onsen中,这没有带来显著的性能优势。 - stpool 提供了使用
ThreadCell
的单线程池STPool
,这比互斥锁保护的池要快得多。这些池可以在线程之间合作地移动,具有获取/释放语义。 - tbox 为
TBox
、TRc
、TSc
添加了API,这些API使用每个类型的全局池。优点是框不需要存储其池的引用,这节省了一点内存,并提高了小对象的局部性。 - st_tbox 为tbox API使用
STPool
,这使stpool
和tbox
成为可能。
st_tbox 是默认的。这启用了最完整的API,具有最佳性能。
性能特征
-
Onsen池针对缓存局部性进行了优化,这在某种程度上也针对单线程使用进行了优化。最好为每个线程创建一个类型的池。
-
TPool
添加了互斥锁以用于多线程情况,但它的性能比单线程池低得多,但在许多情况下仍比std分配器好。尽管如此,仍然可以从局部性中受益。 -
STPool
是单线程的,但可以在线程之间合作地传递,其性能与其他单线程池相当。这在使用TBox
、TRc
或TSc
时尤为重要。
基准测试
Onsen使用criterion进行基准测试,由于Onsen是为单线程应用程序制作的,因此最好在单个CPU核心上锁定并锁定到低于最大频率的某个频率,以提供更一致的结果。在高优先级下,这样就不会太多地受到其他程序的影响。在Linux上,您可以这样做:
sudo renice -15 $$
sudo cpupower -c 1 frequenc-set -f 2.8GHz
taskset 2 cargo bench
将生成target/criterion/report/index.html
。
依赖项
~0–5MB