美文网首页
进程的内存布局

进程的内存布局

作者: 飞翃荷兰人 | 来源:发表于2020-04-12 01:40 被阅读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、代码段:

    • BSS和data段都是存储静态变量和全局变量的空间。区别是BSS段存储没有初始化的
      变量。BSS区是匿名的:不映射自任何文件。如果代码中有static int cntActiveUsers;,那么cntActiveUsers就在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位的虚拟地址空间也是遵守基本规律的。

    相关文章

      网友评论

          本文标题:进程的内存布局

          本文链接:https://www.haomeiwen.com/subject/fmummhtx.html