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

ell*_*iel 0 c memory heap stack

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

#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';
}
Run Code Online (Sandbox Code Playgroud)

看起来my_const_global_var并且my_global_var在低地址区域(000XXXXX在堆之前和之后不久)解决了,但令我惊讶的是,my_stack_var正好在75%左右(大约是bffbdaXX).我猜我的全局/我会得到一个段错误)堆/堆栈变量超过3 GB的内存,所以我做了一个搜索,发现提到了一个3 GB的屏障,但没有提到剩下的1 GB可寻址空间会发生什么.

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

Ros*_*dge 6

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

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

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

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