我有以下代码:
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取消映射内存,但它不会导致。这是什么原因?
答案 0 :(得分:2)
我认为上面的Paramagnetic Croissant的评论被认为是对这一评论的“答案”。通常的做法是malloc()
实现在需要时向操作系统询问更多内存,但是永远不要回复它。对于任何操作系统。
你知道,确实没有需要来“回馈它”。纠缠内核,要求他开辟更多的VM空间并更新内存管理数据结构,这是一项相对昂贵的操作。但是,保持存储并不是真正“花费”太多。 (“释放它们”的成本并没有给你带来任何好处,尤其是如果你向右转并且不得不再次要求它们!)所以,你只需要做一次。
如果您停止使用这些页面,它们最终会被换出,物理资源(页面框架)将自动用于其他目的。 “没有伤害,没有犯规。”但是,如果你突然再次启动使用该存储,那么没有理由在第二(或第三)时间“纠缠内核”。这些页面会再次被换入,然后离开。
答案 1 :(得分:0)
malloc / valloc(malloc的页面大小变体)实际上从虚拟地址空间获取内存地址。这些地址通过特定于特定进程的页表映射到物理地址。在我看来,在[vm] alloc的情况下所有内核都必须这样做:
1)将匿名段附加到流程。
2)将一堆虚拟地址(堆区域)条目与物理页面相关联,当然首次使用时。
在“free”的情况下,它只需要将虚拟内存条目与物理页面解除关联。请注意,由于这些是匿名页面,因此需要关注“数据”需要处理的位置,而mmaping文件可能需要将其转发回磁盘。
物理页面由内存管理器独立跟踪和管理,并受缓存原理(热,冷色等)的控制。因此,不存在自由尝试将内存回馈给内核的问题。因为它只是一个虚拟地址。它会将虚拟地址返回给glibc库,glibc库应该维护虚拟地址块以供特定进程使用。