13个版本
0.3.1 | 2024年3月13日 |
---|---|
0.3.0 | 2024年3月6日 |
0.2.2 | 2024年2月28日 |
0.1.7 | 2024年1月29日 |
0.1.5 | 2023年11月11日 |
#57 in 内存管理
8,201 每月下载量
48KB
869 行
lgalloc
为大对象提供的内存分配器。Lgalloc代表大(对象)分配器。我们拼写为 lgalloc
并发音为 el-gee-alloc。
[dependencies]
lgalloc = "0.2"
示例
use std::mem::ManuallyDrop;
fn main() -> Result<(), lgalloc::AllocError> {
lgalloc::lgalloc_set_config(
lgalloc::LgAlloc::new()
.enable()
.with_path(std::env::temp_dir()),
);
// Allocate memory
let (ptr, cap, handle) = lgalloc::allocate::<u8>(2 << 20)?;
// SAFETY: `allocate` returns a valid memory region and errors otherwise.
let mut vec = ManuallyDrop::new(unsafe { Vec::from_raw_parts(ptr.as_ptr(), 0, cap) });
// Write into region, make sure not to reallocate vector.
vec.extend_from_slice(&[1, 2, 3, 4]);
// We can read from the vector.
assert_eq!(&*vec, &[1, 2, 3, 4]);
// Deallocate after use
lgalloc::deallocate(handle);
Ok(())
}
详细信息
- Lgalloc提供了一种为2的幂次方大小的内存区域提供分配器的功能。
- 请求的容量可以向上舍入到更大的容量。
- 内存可以被重新用于其他目的,例如支持一个向量,但是调用者需要小心,永远不要使用特定的分配器来释放内存。
- 内存不会被取消映射,但可以用后台线程懒加载地标记为未使用。具体选项还需要确定。
- 分配是从文件中映射的,这使得操作系统可以在不使用交换的情况下进行分页。
- 在Linux上,这意味着它只能处理常规页面(4KiB),该区域不能使用大页面进行映射。
- 当所有区域都释放时,库不会消耗物理内存,但会污染虚拟地址空间,因为它不会取消映射区域。这是因为库没有跟踪映射的哪些部分仍在使用中。
- 通常,自行承担风险,因为没有人应该编写内存分配器。
- 性能似乎合理,在不访问数据时与系统分配器相似,在访问数据时更快。原因是这个库不会取消映射其区域。
分配器试图最小化竞争。它依赖于线程局部分配和一个工作窃取模式来在不同线程之间移动分配。
我们使用术语“区域”来指代2的幂次方大小的分配,而“区域”则指连续的分配。每个区域可以支持多个区域。
- 每个线程维护一个有限的区域缓存。
- 如果分配时缓存为空,它首先检查全局池,然后是其他线程。
- 全局池有脏和干净两种变体。脏包含最近回收的分配,而干净包含我们标记为不再需要/从操作系统中删除的分配。
- 可选的后台工作员会定期将分配从脏移动到干净。
- Lgalloc大量使用
crossbeam-deque
,它提供了一个无锁的工作窃取API。 - 补充区域是一个同步操作。它需要创建一个文件、分配空间并映射其内容。每次大小类别为空时,我们都会将分配的大小加倍。
- Lgalloc会报告关于分配、释放和补充的指标。
待办事项
- 测试非常有限。
- 分配加倍大小的区域似乎会压力测试
mmap
系统调用。考虑不同的策略,例如固定大小的块或限制我们分配的区域。区域大小和区域数量之间可能存在权衡。 - 固定大小的区域可能允许我们在大小类别之间移动区域。
- 引用计数可以确定区域不再被引用,尽管这并不简单,因为这是一个无锁系统。
许可证
根据您的选择,此软件根据Apache License, Version 2.0或MIT许可证授权。除非您明确表示,否则,根据Apache-2.0许可证定义的,您有意提交以包含在此软件包中的任何贡献,将如上双授权,无任何附加条款或条件。
依赖项
~2–12MB
~134K SLoC