尽管使用了引用,但函数使用过多的内存

Function using too much memory despite using references

提问人:Shane 提问时间:7/8/2023 最后编辑:Shane 更新时间:7/8/2023 访问量:68

问:

我有一个函数(准确的方法),其主要目的是压缩多个向量(类似于 Python 中的函数)。zip

变量的两个向量都非常大,但考虑到这些是引用向量,我相信内存使用不会成为问题。我错了,此代码经常遇到内存分配问题并由于内存不足而崩溃。windows

当代码立即命中受存储 IO 限制的分页内存时,任何性能改进都会被抹去。

我尝试了代码的几种变体,但它们似乎都遇到了同样的问题。

在我的理解中,唯一的大内存分配发生在创建变量时(发生在不同的方法中)。完成初始分配后,该方法中不应发生额外的大型分配,因为它仅处理对原始数据的引用。这是正确的理解吗?windowscreate_zipped_kmers

我在代码中是否做错了什么,或者我的知识存在差距?如何在保持性能的同时减少内存使用量?

变体 1

    fn create_zipped_kmers(&'a self, windows: &'a Vec<Vec<&'a str>>) -> Vec<Vec<&'a str>> {
        if windows.is_empty() {
            panic!("Sequence k-mer vector cannot be empty");
        }

        let num_cols = windows.iter().map(|v| v.len()).min().unwrap_or(0);
        let num_rows = windows.len();

        let mut zipped = Vec::with_capacity(num_cols);
        for col_index in 0..num_cols {
            let column: Vec<&str> = (0..num_rows)
                .into_par_iter()
                .map(|row_index| windows[row_index][col_index])
                .collect();
            zipped.push(column);
        }

        zipped
    }

变体 2

    fn create_zipped_kmers(&'a self, windows: &'a Vec<Vec<&'a str>>) -> Vec<Vec<&'a str>> {
        if windows.is_empty() {
            panic!("Sequence k-mer vector cannot be empty");
        }

        let num_cols = windows.iter().map(|v| v.len()).min().unwrap_or(0);
        let num_rows = windows.len();

        (0..num_cols)
            .into_par_iter()
            .map(|col_index| {
                (0..num_rows)
                    .map(|row_index| windows[row_index][col_index])
                    .collect::<Vec<&str>>()
            })
            .collect()
    }

变体 3

    fn create_zipped_kmers(&'a self, windows: &'a Vec<Vec<&'a str>>) -> Vec<Vec<&'a str>> {
        if windows.is_empty() {
            panic!("Sequence k-mer vector cannot be empty");
        }

        let num_seqs = windows[0].len();
        let mut iters: Vec<_> = windows.par_iter().map(|n| n.into_iter()).collect();

        (0..num_seqs)
            .map(|_| {
                iters
                    .par_iter_mut()
                    .map(|n| *n.next().unwrap())
                    .collect()
            })
            .collect()
    }

谢谢。

色人造丝

评论

0赞 kmdreko 7/8/2023
我们能得到一些数字吗?有多少个向量,这些向量中有多少个元素?您有多少内存,有多少内存已经在使用中?windows
0赞 Shane 7/8/2023
@kmdreko外向量包含 2293158 个向量,其中每个向量包含 1308 &str。我有 30GB 的系统内存。
1赞 kmdreko 7/8/2023
避免 #3,因为这涉及预先收集 200 万个迭代器。另外两个在内存使用方面应该大致相同。#2 对我来说看起来最好,只是基于在哪里,但一如既往,衡量!.into_par_iter()
2赞 Dogbert 7/8/2023
@Shane您的输入至少为 48GB,输出也至少为 48GB,加上字符串的基础数据占用的内存,加上数百万 Vec 的开销。您需要的远不止 90GB,可能至少 100GB + 所有字符串占用的字节总和。
1赞 Dogbert 7/8/2023
@Shane Vec 需要 3 个字(64 位为 24 个字节),加上分配的内存量 (),这可能取决于您创建向量的方式。我建议先加载更少的数据,然后看看它在您的机器上消耗了多少。vec.capacity() * size of each element.len()

答: 暂无答案