linux内核-写时复制之实验+源码分析
实验
相信大家都听过大名鼎鼎的copy on write技术,并且学习过原理。但是可能对于代码中具体的发生场景,脑海中可能没有实体的映射。下面使用1个例子说明copy on write的发生时间。
有这么一个程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>// 打印当前进程的内存占用(常驻集大小)
void print_memory_usage(const char* stage) {FILE* file = fopen("/proc/self/status", "r");if (!file) {perror("fopen");return;}char line[256];while (fgets(line, sizeof(line), file)) {if (strncmp(line, "VmRSS:", 6) == 0) {printf("[%s] Memory Usage (VmRSS): %s", stage, line + 6);break;}}fclose(file);
}int main() {size_t size = 100 * 1024 * 1024; // 分配 100 MBvoid* ptr = malloc(size);if (!ptr) {perror("malloc");return 1;}printf("Step 1: After malloc (before memset)\n");print_memory_usage("After malloc");sleep(3); // 给用户一点时间观察memset(ptr, 0, size); // 写入触发物理内存分配printf("Step 2: After memset (after touching memory)\n");print_memory_usage("After memset");sleep(3); // 给用户一点时间观察free(ptr);printf("Step 3: After free\n");print_memory_usage("After free");return 0;
}
编译+运行
编译:
gcc do_copy_on_write.c -o do_copy_on_write
运行:
./do_copy_on_write
各部分说明
1. 分配内存(malloc)
void* ptr = malloc(size);
分配了一块大小为 100MB 的虚拟内存。此时操作系统只分配了虚拟地址空间,并没有实际分配物理内存页(因为还没有使用它)。程序紧接着打印此时的内存使用情况(VmRSS):
print_memory_usage("After malloc");
2.让程序睡眠3秒
-
程序会
sleep(3)
秒,可以有时间手动观察或记录当前内存(可以用top
、htop
或查看程序输出)。 -
你会发现此时内存几乎没有明显增长,只有很小的常驻内存(程序自身的开销)。
3. 访问内存触发分配(memset)
memset(ptr, 0, size);
-
使用
memset
将这 100MB 全部设置为 0,相当于每个内存页都被写入了一次。 -
这会触发操作系统的延迟物理页分配机制,因为每个页第一次被写入,就必须真正分配物理内存。
-
然后再次调用
print_memory_usage
打印新的VmRSS
,这时你会看到内存暴涨到 100MB 左右。
4. 最后释放内存
整个程序完整的输出为:
./a.out
Step 1: After malloc (before memset)
[After malloc] Memory Usage (VmRSS): 952 kB
Step 2: After memset (after touching memory)
[After memset] Memory Usage (VmRSS): 103912 kB
Step 3: After free
[After free] Memory Usage (VmRSS): 1536 kB
源码分析
TODO