【问题标题】:Does mmap or malloc allocate RAM?mmap 或 malloc 是否分配 RAM?
【发布时间】:2014-02-02 20:54:15
【问题描述】:

我知道这可能是一个愚蠢的问题,但我一直在寻找一段时间,无法找到明确的答案。如果我使用mmapmalloc(在C 语言中,在Linux 机器上),是否其中一个会在RAM 中分配空间?例如,如果我有 2GB 的 RAM 并且想使用所有可用的 RAM,我可以只使用 malloc/memset 组合、mmap,还是有其他我不知道的选项?

我想编写一系列简单的程序,它们可以同时运行并保留进程中使用的所有 RAM 以强制使用交换,并频繁换入/换出页面。我已经用下面的程序试过了,但这并不是我想要的。它确实分配内存(RAM?),并强制使用交换(如果有足够的实例正在运行),但是当我调用sleep 时,这并不仅仅锁定内存不被使用(所以实际上没有任何东西被交换或从其他进程中出来?),还是我误解了什么。

例如,如果我运行 3 次,我将使用前两个实例的 2GB(全部)RAM,然后第三个实例将前两个实例中的一个交换出(RAM)和当前实例进入内存?还是实例 #3 只使用磁盘或虚拟内存运行?

这又带来了一点,我是否需要分配足够的内存来使用所有可用的虚拟内存以及要使用的交换分区?

最后,mmap(或任何其他 C 函数。地狱,如果适用的话,甚至是另一种语言)会更好吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

#define MB(size) ( (size) * 1024 * 1024)
#define GB(size) ( (size) * 1024 * 1024 * 1024)


int main(){
    char *p;
    p = (char *)malloc(MB(512));
    memset(p, 'T', MB(512));
    printf(".5 GB allocated...\n");

    char *q;
    q = (char *)malloc(MB(512));
    memset(q, 'T', MB(512));
    printf("1 GB allocated...\n");
    printf("Sleeping...\n");

    sleep(300);
}

** 编辑:我正在为我的操作系统使用 CentOS 6.4(带有 3.6.0 内核),如果有帮助的话。

【问题讨论】:

  • 我建议查看 mlock()mlockall(),因为他们在文档中说他们可以将进程的虚拟地址空间锁定到 RAM 中。
  • 非常依赖于操作系统,但由于操作系统管理优先级,我认为如果您加载另一个程序,RAM 将不会继续使用,运行的程序将使用 RAM,其他程序将去交换
  • 这里有一个更详细的解释,如果你想更详细:stackoverflow.com/questions/2688466/… [1]:stackoverflow.com/questions/2688466/…
  • "只使用磁盘或虚拟内存运行" - 请注意,这些不是替代方案。虚拟内存描述了将底层存储从您手中抽象出来的整个操作系统机制。数据可以物理存储在磁盘或 RAM 中,或者根本不存储(在未提交内存的情况下)。

标签: c linux memory malloc mmap


【解决方案1】:

这里的理论和实践差别很大。理论上,mmapmalloc 都不会分配实际的 RAM,但实际上它们会分配。

mmap 将分配 RAM 来存储虚拟内存区域数据结构 (VMA)。如果mmap 与要映射的实际文件一起使用,它将(除非明确说明不同)进一步分配几页 RAM 来预取映射文件的内容。
除此之外,它只保留地址空间,RAM将在第一次访问时分配。

malloc 类似地,通过sbrkmmap 告诉操作系统它想要管理一些(通常比你大请求)地址空间的区域。然后,它通过某种或多或少复杂的算法细分这个巨大的区域,最后保留一部分地址空间(正确对齐和舍入)供您使用,并返回一个指向它的指针。
但是: malloc 还需要在某处存储一些额外的信息,否则free 将无法在以后完成它的工作。除了起始地址之外,至少free 需要知道分配块的大小。通常,malloc 因此会秘密分配一些额外的字节,这些字节紧接在您获得的地址之前——您不知道,它不会告诉您。

现在问题的症结在于,虽然 理论上 malloc 不会触及它管理的内存并且不会分配物理 RAM,但 实际上它会 .这确实会导致页面错误和内存页面被创建(即正在使用 RAM)。
您可以在 Linux 下通过继续调用 malloc 来验证这一点,然后观察 OOP 杀手将您的进程炸毁,因为系统耗尽了物理 RAM,而实际上 应该 还剩很多。 p>

【讨论】:

  • 附带说明,当分配更细粒度时,malloc() RAM 消耗会更严重。
【解决方案2】:

这非常依赖于操作系统/机器。

在大多数操作系统中,它们都不分配 RAM。它们都分配 VM 空间。它们使一定范围的进程虚拟内存可供使用。 RAM 通常在第一次写入时由操作系统稍后分配。在那之前,这些分配不使用 RAM(除了将它们列为有效 VM 空间的页表)。

如果要分配物理 RAM,则必须使每个页面(sysconf(_SC_PAGESIZE) 为您提供系统页面大小)变脏。

在 Linux 中,您可以在 /proc/self/smaps 中查看包含所有详细信息的 VM 映射。 Rss 是该映射的常驻集(RAM 中有多少常驻),其他所有脏的都将被换出。所有非脏内存都可以使用,但在那之前不会存在。

你可以用类似的东西弄脏所有页面

size_t mem_length;
char (*my_memory)[sysconf(_SC_PAGESIZE)] = mmap(
      NULL
    , mem_length
    , PROT_READ | PROT_WRITE
    , MAP_PRIVATE | MAP_ANONYMOUS
    , -1
    , 0
    );

int i;
for (i = 0; i * sizeof(*my_memory) < mem_length; i++) {
    my_memory[i][0] = 1;
}

在某些实现中,这也可以通过将MAP_POPULATE 标志传递给mmap 来实现,但是(取决于您的系统)如果您尝试映射更多,则它可能会失败mmapENOMEM内存可用。

【讨论】:

  • smaps 中的标题格式是什么?例如,第一行是“00400000-0040b000 r-xp 00000000 fd:00 1048608”我假设前两个是物理内存中的开始/结束地址,如果是,其他是什么?
  • @cHam 所有地址都是虚拟机地址。您不会在任何地方找到物理地址,因为这些地址会随着时间而改变。 r-xp 是权限(在这种情况下为读取/执行/私有)。零是底层映射文件的偏移量(如果适用),底层文件/设备映射的设备描述符。最后一个是映射设备的inode,如果不适用则为0。详情请咨询linux.die.net/man/5/proc
  • 你对如何让每个页面变脏有什么建议吗?我不确定我应该如何处理 (sysconf(_SC_PAGESIZE))...
  • @cHam 添加了编辑。您基本上必须写入每一页。 sysconf(_SC_PAGESIZE) 是您系统的页面大小。操作系统仅在页面块中分配内存。 mmap 总是分配与页面大小对齐的内存。
猜你喜欢
  • 2017-12-15
  • 2014-04-24
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2015-08-13
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
相关资源
最近更新 更多