为什么不自由执行munmap?

时间:2015-05-13 15:36:15

标签: linux-kernel mmap strace

我有以下代码:

     unsigned char *p = (unsigned char *)valloc(page_size);
     if (!p) {                 
             ret = -1;
             goto out;
     }
     printf("valloc: allocated %d bytes, virtual address: %p\n", page_size, p);

     memset(p, 0xFF, page_size);
     memcpy(p, s, sizeof(s));

     trace_mem(p, sizeof(s));
     printf("Memory: %p -  press any key\n", p);
     getchar();

     if (ioctl(fd, MY_IOC_PATCH) == -1) {
            fprintf(stderr, "ioctl %s error(%d): %s\n ", "MY_IOC_PATCH", errno, strerror(errno));
            ret = -1;
            goto out;
     }

     if (p) {
             printf("free: freed %d bytes, virtual address: %p\n", page_size, p);
             free(p);
     }
      .........................

然后我用strace来观察系统调用:strace ./my_program我得到以下内容:

fstat64(1, {st_mode=S_IFREG|0644, st_size=1533, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =      0xb7730000
brk(0)                                  = 0x9d81000
brk(0x9da4000)                          = 0x9da4000
fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb772f000
read(0, "\n", 1024)                     = 1
ioctl(3, RTC_IRQP_SET, 0x1000)          = 0
read(0, "\n", 1024)                     = 1
ioctl(3, RTC_EPOCH_READ, 0x9d82000)     = 0
read(0, "\n", 1024)                     = 1
close(3)                                = 0
valloc: allocated 4096 bytes, virtual address: 0x9d82000

在第一个IOCTL之后,我没有看到munlock。我想free必须使用munlock取消映射内存,但它不会导致。这是什么原因?

2 个答案:

答案 0 :(得分:2)

我认为上面的Paramagnetic Croissant的评论被认为是对这一评论的“答案”。通常的做法是malloc()实现在需要时向操作系统询问更多内存,但是永远不要回复它。对于任何操作系统。

你知道,确实没有需要来“回馈它”。纠缠内核,要求他开辟更多的VM空间并更新内存管理数据结构,这是一项相对昂贵的操作。但是,保持存储并不是真正“花费”太多。 (“释放它们”的成本并没有给你带来任何好处,尤其是如果你向右转并且不得不再次要求它们!)所以,你只需要做一次

如果您停止使用这些页面,它们最终会被换出,物理资源(页面框架)将自动用于其他目的。 “没有伤害,没有犯规。”但是,如果你突然再次启动使用该存储,那么没有理由在第二(或第三)时间“纠缠内核”。这些页面会再次被换入,然后离开。

答案 1 :(得分:0)

malloc / valloc(malloc的页面大小变体)实际上从虚拟地址空间获取内存地址。这些地址通过特定于特定进程的页表映射到物理地址。在我看来,在[vm] alloc的情况下所有内核都必须这样做:

1)将匿名段附加到流程。

2)将一堆虚拟地址(堆区域)条目与物理页面相关联,当然首次使用时。

在“free”的情况下,它只需要将虚拟内存条目与物理页面解除关联。请注意,由于这些是匿名页面,因此需要关注“数据”需要处理的位置,而mmaping文件可能需要将其转发回磁盘。

物理页面由内存管理器独立跟踪和管理,并受缓存原理(热,冷色等)的控制。因此,不存在自由尝试将内存回馈给内核的问题。因为它只是一个虚拟地址。它会将虚拟地址返回给glibc库,glibc库应该维护虚拟地址块以供特定进程使用。