11个不稳定版本 (3个重大更改)

0.4.3 2020年8月9日
0.4.2 2020年4月24日
0.3.1 2020年4月23日
0.3.0 2020年3月10日
0.1.0 2019年11月26日

#262 in 内存管理

Download history 1543/week @ 2023-11-23 1636/week @ 2023-11-30 1720/week @ 2023-12-07 1332/week @ 2023-12-14 688/week @ 2023-12-21 314/week @ 2023-12-28 896/week @ 2024-01-04 2184/week @ 2024-01-11 4981/week @ 2024-01-18 5808/week @ 2024-01-25 6042/week @ 2024-02-01 4160/week @ 2024-02-08 8197/week @ 2024-02-15 9903/week @ 2024-02-22 12810/week @ 2024-02-29 2939/week @ 2024-03-07

每月下载量34,853
9 个库中使用 (8 个直接使用)

MPL-2.0+

69KB
1.5K SLoC

refpool

refpool是对Rust的std::boxed::Boxstd::rc::Rc的重实现,它使用可重用内存池来加速重新分配。

速度快吗?

当内存池非空时,它在Linux系统上大约比系统分配器快两倍,在Windows系统上快六倍。对于某些数据类型,收益甚至更高。

文档

许可证

版权所有2019年Bodil Stokke

本软件受Mozilla公共许可证第2.0版条款约束。如果此文件未附带MPL副本,您可以从http://mozilla.org/MPL/2.0/获取。

行为准则

请注意,该项目附带贡献者行为准则。通过参与此项目,您同意遵守其条款。


lib.rs:

使用可重用内存池加速重新分配的std::boxed::Boxstd::rc::Rc的重实现。

先决条件

要从内存池中初始化一个类型到其默认值,请使用 PoolBox::default()PoolRef::default() 方法,需要实现 PoolDefault

如果想要使用 PoolRef::make_mut() 方法,还需要实现 PoolClone

使用 PoolRef::new() 方法构建值时,没有要求。

对于大多数原始类型和 std 的数据类型,都实现了 PoolDefaultPoolClone,您可以轻松地为自定义类型提供默认实现,通过实现标记特质 PoolDefaultImpl。如果您有不需要在构造时完全初始化内存的数据结构,也可以自行实现,这可以带来轻微的性能提升。(这种优化是为什么 PoolDefaultPoolClone 作为独立的特质存在,否则 DefaultClone 就足够了。)

使用方法

您可以通过调用 PoolRef::default(pool)PoolRef::new(pool, value) 来创建新值。如果可用,这将使用池中的内存,如果池为空,则回退到正常的堆分配。当引用值的最后一个 PoolRef 被丢弃时,其分配的内存将返回到池中。

BoxRc 的区别

PoolBoxBoxPoolRefRc 兼容 API,有以下例外

线程安全

Pool 是严格线程本地的,即它不实现 Sync,如果你仍然设法从两个不同的线程访问它,它将以令人震惊的方式失败。没有 Arc 的等效,因为向池中添加线程安全会降低性能,以至于池不再提供显著的性能优势,即使是在野外的最慢的系统分配器(我指的是 Windows)也不例外。

性能

你可以期望 Pool 总是优于系统分配器,尽管性能提升在不同平台上会有所不同。初步基准测试显示,它在 Linux 上的速度大约快两倍,在 Windows 上快 5-6 倍。像 jemalloc 这样的自定义分配器可能会产生更小的效益,但你几乎不可能找到一个能超越池的分配器。

对于具有有益的 PoolDefaultPoolClone 实现的数据类型,你可以期望获得更大的性能提升,“有益”的意思是指可以不初始化分配的内存的大部分情况。例如,sized_chunks::Chunk,它在 64 位平台上分配 528 字节,但只需要初始化其中的 16 个用于 PoolDefault

示例

// Create a pool of `usize` with a max size of 1 (for argument's sake).
let mut pool: Pool<usize> = Pool::new(1);

{
    // Create a reference handle to a usize initialised to 0.
    // The pool starts out empty, so this triggers a normal heap alloc.
    let value_ref = PoolRef::default(&mut pool);
    assert_eq!(0, *value_ref); // You can deref it just like `Rc`.
} // `value_ref` is dropped here, and its heap memory goes on the pool.

// Check that we do indeed have one allocation in the pool now.
assert_eq!(1, pool.get_pool_size());

// Create another reference and initialise it to 31337, a good round number.
// This will reuse `value_ref`'s memory.
let another_value_ref = PoolRef::new(&mut pool, 31337);
assert_eq!(31337, *another_value_ref);

// Check that the pool is again empty after we reused the previous memory.
assert_eq!(0, pool.get_pool_size());

功能标志

目前有一个功能标志可用,即 default_impl,它需要一个夜间编译的 rustc,因为它依赖于 min_specialization 语言特性,该特性删除了 PoolDefaultImpl 特性,并为任何实现了 CloneDefault 的类型的 PoolClonePoolDefault 提供了一个可覆盖的默认实现。 PoolDefaultImpl 是一个不幸的漏洞,用于绕过当前稳定 rustc 中缺乏特殊化的情况。

没有运行时依赖