#vector #disk #memory #big #allocate #disk-alloc

nightly diskallocator

对于非常大的向量:在磁盘上分配

2个版本

0.1.1 2023年4月20日
0.1.0 2023年4月19日

#382内存管理

27 每月下载

MIT 许可证

14KB
244 代码行

DiskAlloc

对于非常大的向量:在磁盘上分配。

动机

如果您有非常大的向量,您可能希望将它们保存在磁盘上而不是内存中。
似乎没有绕过序列化和反序列化的方法,但使用这个crate,您可以直接在磁盘上分配“内存”!

它是如何工作的?

Linux提供文件的内存映射。这意味着您可以有一个1TB大小的文件,将其映射到用户空间的地址,并像实际拥有1TB内存一样使用它。

操作系统会根据需要交换页面,并处理所有这些。

向量通常加倍和减半大小。
这个crate首先在内存中映射了一个0B文件的512GiB。
如果您的向量需要调整大小,DiskAlloc会根据您的需求增长或缩小文件。映射不一定保证是可增长的,这就是为什么它必须从一开始就非常大。

陷阱

进行I/O操作可能会失败。
因此,如果您想确保向量的调整大小不会使整个程序崩溃,则应使用 Vec::try_reserve()

此外,请注意在堆上存储数据的结构。
Vec<String> 保留所有内容在堆上,只会存储指向堆上字符串的指针在磁盘上,这在任何情况下都没有意义。
请参阅 SmallString 了解如何尽可能将字符串保留在向量本身中。

如果您有可序列化和反序列化的项目,并且可以处理有限的向量功能,请参阅 swapvec

对于每个向量,请使用一个 DiskAlloc 实例。
一旦在单个文件上使用多个向量,所有优化都会消失。

也不要一次性创建过多的 DiskAlloc 实例。
每个映射都需要512GiB的地址范围,所以创建过多会导致 OutOfMemory 错误。

注意

如果您在 htop 中跟踪您的应用程序,您将看到,htop 显示您的进程内存使用量很高。

这包括当前保存在RAM中的数据,但它仍然被计算为文件缓冲区(参见RAM条的黄色部分)。

使用方法

简单且最安全

#![feature(allocator_api)]
use diskallocator::DiskAlloc;

fn main() {
    let alloc = DiskAlloc::new().unwrap();
    let mut v: Vec<u32, DiskAlloc> = Vec::new_in(alloc);

    for i in 0..100 {
        v.push(i);
    }
}

高级

#![feature(allocator_api)]
use std::{fs::OpenOptions, thread, time::Duration};

use diskallocator::DiskAlloc;

// Size 4 bytes * 16 = 64B
struct Dummy {
    _txt: [char; 16],
}

impl Dummy {
    pub fn new() -> Self {
        Self {
            _txt: [
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', '1', '2', '3', '4', '5', '6', '7', '8',
            ],
        }
    }
}

fn main() {
    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("dummy.file")
        .unwrap();
    let alloc = DiskAlloc::on_file(file).unwrap();
    let mut v: Vec<Dummy, DiskAlloc> = Vec::new_in(alloc);

    let giga = 1;
    let items_per_kb = 16;

    for _ in 0..giga * items_per_kb * 1024 * 1024 {
        v.push(Dummy::new());
    }
    println!("Check file dummy.file!");
    // thread::sleep(Duration::from_secs(999999));
}

依赖关系

~1.6–9.5MB
~105K SLoC