在C++中,虚拟内存分为代码段、数据段、BSS段、堆区、栈区和文件映射区六部分。
代码段:包括只读储存区和文本区,其中只读储存区储存字符串常量,文本区储存程序的机器代码。
数据段:储存程序中已初始化的全局变量和静态变量。
BSS段:储存未初始化的全局变量和静态变量,以及所有被初始化为0的全局变量和静态变量。
堆区:调用new/malloc函数时在堆区分配动态内存,同时需要delete/free释放内存。
栈区:使用栈空间储存函数的返回地址、参数、局部变量、返回值。
映射区:储存动态链接库以及调用mmap函数时进行的文件映射。
32bitCPU可寻址4G线性空间,每个进程都有各自独立的4G逻辑地址,其中0~3G是用户态空间,3~4G是内核空间,不同进程相同的逻辑地址会映射到不同的物理地址中。其逻辑地址其划分如下:
静态区包括代码段、数据段和BSS段;动态区包括堆区、映射区、栈区。
虚拟地址空间会被CPU逻辑管理单元(MMU)映射到真实物理内存上。
虚拟地址:现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要MMU(Memory Management Unit)的支持。MMU通常是CPU的一部分,如果处理器没MMU,
或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被 内存芯片(物理内存)接收,这称为物理地址(Physical Address),如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将虚拟地址映射成物理地址。
Linux中,进程的4GB(虚拟)内存分为用户空间、内核空间。用户空间分布为0~3GB(即PAGE_OFFSET,在0X86中它等于 0xC0000000),剩下的1G为内核空间。程序员只能使用虚拟地址。系统中每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可的。CPU发出取指令请求时的地址是当前上下文的虚拟地址,MMU再从页表中找到这个虚拟地址的物理地址,完成取指。同样读取数据的也是虚拟地址,比如mov ax, var. 编译时var就是一个虚拟地址,也是通过MMU从也表中来找到物理地址,再产生总线时序,完成取数据的。