进程的内存布局

2020-04-12  本文已影响0人  飞翃荷兰人

在讲进程的内存布局,也就是进程的虚拟地址空间的时候,首先应该对虚拟内存有一定的了解:虚拟内存浅析。下面开始正题。

一 历史进程内存

在原来的32位的操作系统中,由于指针是4个字节,所以它的最大寻址空间就只有4G,进一步的,这4G分为3G的用户空间和1G的内核空间。


image.png

对于32位的cpu来说,进程的虚拟地址空间从高地址到低地址一共分为七段:

(1) 内核空间 : 权限较高

(2) 栈空间:栈里保存了局部变量,以及大多数编程语言中的函数参数。一次方法或函数调用就会向栈增加一个栈帧(stack frame)。当函数返回时栈帧就会被销毁。如果推入栈的数据过多,可能会耗尽栈映射的地址区域。这会导致一次页错误,Linux将其处理为一次expand_stack()调用,实际上是调用acct_stack_growth()检查当前是否可以增加栈大小。如果栈大小小于RLIMIT_STACK(通常8MB)就可以继续增长,程序会正常继续,不会察觉到什么。这是栈大小调整的默认处理。但是,如果栈大小达到了上限,就会发生栈溢出,程序会接到一次段错误(Segmentation Fault)。相对的,当栈变小时,不会缩减栈大小。

(3) mmap段:内核在这里将文件内容映射为内存。通常被用来加载动态链接库。

(4) 堆:堆提供了运行时的内存分配,这点和栈类似。

(5) BSS、data、代码段:


对于现在的64位操作系统,情况已经大不一样了,下面做个小实验:

using namespace std;
static int c = 4;
int main(void) {
    int a = 1;
    int b = 2;
    cout << "栈开始: " << &a << " " << "栈地址减小: " << &b << " " << "BSS段位置: " << &c << endl;
    return 0;
}

结果:
栈开始: 0x7ffee646dad8 栈地址减小: 0x7ffee646dad4 BSS段位置: 0x1097960c0

可以看到,栈起始地址:0x7ffee646dad8,转换为Gb为106万,虚拟地址已经恐怖如斯,可以看到,再在栈上定义一个变量b,栈空间向下减小4个字节。静态全局变量c的地址为0x1097960c0,远远小于栈地址,可以看到即使是64位的虚拟地址空间也是遵守基本规律的。

上一篇 下一篇

猜你喜欢

热点阅读