Linux中为何仅写操作不分配物理RAM,读写结合操作才分配?
为什么Linux中仅写操作不分配物理RAM,读写结合才会分配?
问题背景
在Linux 5.4(aarch64架构)下,使用gcc 6.3.1编译以下代码时发现:
- 使用
ptr[i] += 1(先读后写)会触发物理RAM分配 - 使用
ptr[i] = 1(仅写操作)则不会分配物理RAM
int main(int argc, char *argv[]) { long size; long size_bytes; char *ptr; size = strtol(argv[1], NULL, 0); size_bytes = size * 1024 * 1024; ptr = malloc(size_bytes); if (!ptr) goto exit; // 将内存标记为脏页以分配实际物理RAM for (int i = 0; i < size_bytes; i += sysconf(_SC_PAGESIZE)) ptr[i] += 1; // 可正常分配物理RAM //ptr[i] = 1; // 不会分配物理RAM while(1) sleep(1); exit: free(ptr); return 0; }
核心原因:编译器优化导致仅写操作被丢弃
1. malloc内存的初始状态
malloc分配的大内存(超过默认阈值128KB时)会通过mmap创建匿名虚拟映射,此时虚拟地址已分配,但未关联实际物理RAM——内核采用「需求分页」策略,仅当虚拟页被首次访问时才分配物理页。
2. 编译器对无用写操作的优化
gcc会分析代码的实际副作用:
- 对于
ptr[i] = 1:程序后续没有读取或使用ptr指向的内存,编译器判定这个写操作是「无意义的冗余操作」,直接在编译阶段删除了整个循环。没有循环执行,自然不会触发任何虚拟页访问,也就不会分配物理RAM。 - 对于
ptr[i] += 1:这个操作包含「读取ptr[i]原有值」的步骤,编译器无法完全确定该操作是否有隐藏副作用(例如,内存地址是否被其他线程或硬件访问),因此不会优化掉循环。循环执行时,每个页的首字节被访问,触发缺页异常,内核随即分配对应物理RAM并完成映射。
验证方法
如果想让仅写操作也触发物理RAM分配,可以通过volatile关键字阻止编译器优化:
for (int i = 0; i < size_bytes; i += sysconf(_SC_PAGESIZE)) *(volatile char*)&ptr[i] = 1; // 强制保留写操作,触发物理页分配
此时编译器会保留循环,执行写操作时触发缺页异常,内核分配物理RAM。
补充:内核需求分页的细节
当虚拟页被首次访问(读/写)时,会触发缺页异常:
- 内核检查虚拟页的状态,确认是未分配物理页的匿名映射
- 分配物理页,将虚拟页与物理页建立映射
- 恢复程序执行,完成读写操作
如果没有实际的内存访问(循环被优化掉),这个流程就不会启动,物理RAM自然不会被分配。
内容的提问来源于stack exchange,提问作者101ful
相关产品推荐
相关产品推荐

