gpt4 book ai didi

c - 保留内存等于共享内存,但从不保留内存

转载 作者:行者123 更新时间:2023-12-04 08:00:04 25 4
gpt4 key购买 nike

我目前正在编辑一个我继承的程序,以便能够处理 23 GB 的文件。因此,为了保持低内存,我使用 mmap加载我在以前的程序中创建的数组。但是,我加载了这些数组,然后进入一个函数,共享和保留的内存会出现峰值,尽管我不相信我曾经分配过任何东西。运行时,内存从 0 开始,然后迅速增加到 90%(大约 36GB,因为我有 40GB 的内存)并保持在那里。最终,我开始需要内存(小于 30GB),然后程序就被杀死了。
通常,我会怀疑这个问题是由于分配引起的,或者我以某种方式分配了内存。但是,我没有分配任何内存(尽管我正在阅读 mmap ed 文件)。
奇怪的是,保留的内存等于共享的内存量(见附件截图)。
Output
我为访问 mmaped 数组而编写的函数:

double* loadArrayDouble(ssize_t size, char* backupFile, int *filedestination) {
*filedestination = open(backupFile, O_RDWR | O_CREAT, 0644);
if (*filedestination < 0) {
perror("open failed");
exit(1);
}
// make sure file is big enough
if (lseek(*filedestination,size*sizeof(double), SEEK_SET) == -1) {
perror("seek to len failed");
exit(1);
}

if (lseek(*filedestination, 0, SEEK_SET) == -1) {
perror("seek to 0 failed");
exit(1);
}

double *array1 = mmap(NULL, size*sizeof(double), PROT_READ | PROT_WRITE, MAP_SHARED, *filedestination, 0);
if (array1 == MAP_FAILED) {
perror("mmap failed");
exit(1);
}

return array1;
}

请让我知道是否有任何其他代码要包含..即使 double* file1 = loadArrayDouble(SeqSize, "/home/HonoredTarget/file1", &fileIT); 似乎内存显着增加。被多次调用(对于 6 个数组中的每一个)

最佳答案

“Res”是“resident”的缩写,不是“reserved”。常驻内存是指内核恰好驻留在此刻的进程内存;虚拟内存系统可能会随时删除常驻页面,因此这绝不是限制。但是,内核试图不换出似乎处于事件状态的页面。如果您的进程在内存中搅动了太多页面,OOM 杀手就会起作用。如果您按顺序使用数据,那么您已经进行了多少 mmap'ed 通常并不重要,因为只有最近的页面才会被驻留。但是如果你在内存中跳过,在这里读一点,在那里写一点,那么你会创造更多的流失。这似乎是正在发生的事情。
“shr”(共享)内存实际上是指可以与另一个进程共享的内存(无论它是否真的与另一个进程共享)。您使用的事实 MAP_SHARED意味着您的所有 mmap'ed 页面都被共享也就不足为奇了。您需要 MAP_SHARED如果您的程序修改了文件中的数据,我猜是这样。
“virt”(虚拟)列衡量您实际映射的地址空间(包括您使用的任何动态分配库映射到匿名后备存储的内存。)170G 对我来说似乎有点高。如果您同时映射了 6 个 23GB 的文件,那就是 138GB。但也许这些数字只是估计。无论如何,只要您在设置的虚拟内存限制范围内,就没有那么重要了。 (虽然页表确实会占用实内存,所以还是有一定效果的。)
内存映射并不会节省您的内存,真的。当你映射一个文件时,文件的内容仍然需要被读入内存以便你的程序使用这些数据。 mmap 的一大优势是您不必费心分配缓冲区和发出读取调用。此外,无需从读取文件的内核缓冲区复制数据。所以它可以更容易、更高效,但并非总是如此;这在很大程度上取决于精确的访问模式。
需要注意的一件事:以下代码段没有执行评论所说的那样:

    // make sure file is big enough
if (lseek(*filedestination,size*sizeof(double), SEEK_SET) == -1) {
perror("seek to len failed");
exit(1);
}
lseek只为下一个读或写操作设置文件位置。如果文件没有扩展到那个点,你会在读取时得到一个 EOF 指示,或者如果你写入文件将被扩展(稀疏)。所以真的没有多大意义。如果要检查文件大小,请使用 stat .或者确保在执行搜索后至少读取一个字节。
使用 O_CREAT 也没什么意义在 open调用,因为如果文件不存在并因此被创建,它的大小将为 0,这可能是一个错误。离开 O_CREAT关闭表示 open如果文件不存在,调用将失败,这可能是您想要的。
最后,如果您实际上没有修改文件内容,请不要使用 PROT_WRITE 进行映射。 . PROT_READ内核处理页面要容易得多,因为它们可以被删除并稍后读回。 (对于可写页面,内核会跟踪页面已被修改的事实,但如果您不打算写入并且不允许修改,这会使内核的任务更容易一些。)

关于c - 保留内存等于共享内存,但从不保留内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66522905/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com