繁体   English   中英

映射的文件在读取时不会占用内存,但在写入时会占用内存

[英]Mapped file doesn't take memory on read, but does on write

我观察到一种怪异的行为,其中一个大内存映射文件(2GB)在我从中读取时并没有占用实际的物理RAM,但是当我开始对其进行写入时却会占用。

int err = 0;

int fd = open("large_file", O_RDWR);
if (fd == -1) {
    return errno;
}

void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, 
                 MAP_PRIVATE, fd, 0); 
if (map == MAP_FAILED) {
     err = errno;
     goto out;
}

for (unsigned int i = 0; i < 2 << 30; i += PAGE_SIZE) {
      volatile uint8_t val = 0xff;

      // val = ((volatile uint8_t *) map)[i]; /* Doesn't take actual memory */
      // ((volatile uint8_t *) map[i]) = val; /* Takes actual memory */
}

while (1)
    sleep(10);

out:
   if (fd != -1)
      close(fd);
   if (map != MAP_FAILED)
      munmap(map, size);
return err;

这是我从映射文件读取时的htop屏幕截图(查看“检查”)

这是我写入映射文件时的htop屏幕截图(查看“检查”

我的笔记本电脑几乎是闲置的,除了测试过程外没有其他东西可以占用物理内存,因此您可以看到当我写入映射文件时实际上需要2GB(写时复制),而在读取时却不需要。 RES-SHR也适合我的两种情况。

我无法解释..内核映射新页面,无论它是对物理RAM的读取还是写入。 如果不存在,则应将其映射,并在出现页面错误异常后获取实际的RAM。 映射的文件映射到其他进程,因此不共享。 测试过程是将文件映射到内存的唯一过程,也是第一个过程。

编辑:我添加了(volatile)关键字,以确保编译器不会优化关键代码。 这没有任何区别。 这段特定的汇编代码是从内存映射文件读取的输出:

mov    BYTE PTR [rbp-0xbd],0xff /* volatile uint8_t val = 0xff; */
mov    edx,DWORD PTR [rbp-0xbc] 
mov    rax,QWORD PTR [rbp-0xb0]
add    rax,rdx
movzx  eax,BYTE PTR [rax]     
mov    BYTE PTR [rbp-0xbd],al   /* val = ((volatile uint8_t *)map)[i]; */
add    DWORD PTR [rbp-0xbc],0x1000 /* i += PAGE_SIZE; */

有什么想法吗?

可能您的编译器只是优化了读取访问。 可以做到这一点,因为您永远不会做任何事情。 最简单的是更改val的声明:

uint8_t volatile val = ... ;

但您也可以相应地声明map

uint8_t volatile*map = mmap(NULL, size, PROT_READ | PROT_WRITE, 
             MAP_PRIVATE, fd, 0);

(声明map类型也可以避免稍后再进行讨厌的转换。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM