i386 C进程 - 剩下的1 GB可寻址空间会发生什么?

时间:2014-09-17 14:51:00

标签: c memory stack heap

据记载,在堆上分配的变量存储在低地址区域中并向堆栈增长,反之亦然。我决定测试一下:

#include <stdio.h>
#include <stdlib.h>

const char my_const_global_var = '0';
char my_global_var = '0';

int main(void) {
    char my_stack_var = '0';
    char* my_heap_var = (char*) malloc(1);
    *my_heap_var = '0';
}

似乎my_const_global_varmy_global_var在低地址区域(000XXXXX之后和堆之前)处理,但让我感到惊讶的是my_stack_var已解决完全大约在75%左右(bffbdaXX)左右。我猜我的全局/堆/堆栈变量超过3 GB内存时会出现段错误,所以我做了搜索并且发现提到了a 3 GB barrier但没有提及剩下的1 GB可寻址空间中会发生什么。

剩下的25%的内存地址空间会发生什么?

1 个答案:

答案 0 :(得分:6)

在32位x86 CPU上运行的保护模式操作系统通常将32位虚拟地址空间划分为两个主要区域。第一个是用户进程,第二个是内核。虚拟地址空间不直接寻址物理内存。相反,它通过内核维护的页表映射到物理内存。这允许操作系统为每个进程提供其自己的虚拟地址空间,将它们彼此隔离。当它切换进程时,它会更改页表,以便虚拟地址空间的用户区指向新进程使用的物理内存位置。

但是,当它切换进程时,操作系统不会更改与内核区域对应的页表条目。这意味着虽然每个进程都有自己的物理内存映射到用户区域,但每个进程的内核区域保持不变。将内核内存映射到每个进程的虚拟地址空间允许在执行系统调用时更快地从用户模式转换到内核模式。如果内核未映射到每个进程,则操作系统基本上必须切换进程(到假设的内核“进程”)以执行系统调用。切换过程比仅从用户模式转换到内核模式要昂贵得多。

大多数64位x86操作系统也有类似的分割,但由于它们具有更大的虚拟地址空间,因此它们将虚拟地址空间划分为更大的块。运行32位程序时,这些操作系统通常可以让程序访问所有或几乎所有前4 GB的虚拟地址空间。

请注意,虚拟内存如何拆分为用户和内核区域不受系统中物理内存量的影响。除非明确配置不同,否则在运行完全相同的操作系统时,只有64 MB RAM的计算机将具有与具有64 GB内存的计算机相同的用户/内核虚拟地址空间。