点击我的视频网校,学习编程课程,或者关注我的微信公众号“编程之路从0到1”,了解课程更新

2.0 内存模型

内存布局

简单模型图:

简单内存布局

内存分区 描述
栈(stack,又称堆栈) 由编译器自动分配和释放,存放函数的参数值、局部变量的值、函数的返回值等。形如数据结构中的栈,具有后进先出的特点。进程的栈空间位于进程用户空间的顶端,并向下扩展。每次函数调用都会在进程栈空间中开辟自己的栈空间,函数返回后,函数的栈空间消失,所以函数返回局部变量的地址是非法的。
堆 (heap) 堆内存是在程序运行过程中分配,一般由程序员手动分配和释放, 若不释放,程序退出时会由操作系统回收。其大小并不固定,可动态扩张或缩减。
数据段(Data segment) 含全局变量和静态变量。可大致分为未初始化数据段.bss)和初始化数据段.data
代码段 (Text segment) 存放 CPU 执行的机器指令。代码区是可以跨进程共享的,在内存中有一份代码即可。且通常也是只读的,以防止程序意外修改其执行。

这里,可对数据区再做一个更细致的划分

分区 描述
.bss (Block Started by Symbol) 用来存储未初始化的全局变量和静态变量。而在程序开始执行之前(也就是main()之前),内核会将这部分的数据初始化为0或一个空指针。
.data 用于保存初始化的全局变量和静态静态变量。注意该区不是只读的,变量的值可以在运行时改变。
.rodata(read-only-data) 只读数据段,存储const修饰的全局变量、诸如“Hello World”的字符串常量。编译器会去掉重复的字符串常量,程序的每个字符串常量只有一份,并且是多个进程间共享的,以提高空间利用率。注意,有些嵌入式系统中,rodata放在ROM里,运行时直接读取,而无需要加载到RAM内存

内存布局模型:

内存布局

以Linux 32位系统内存布局为例,其实际内存布局结构如下图:

横向示意图:

对于x86架构的CPU,其栈顶的地址要比栈底低,模型图:

写一段C代码来验证上述结论

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

int g_var1;      // 未初始化的全局变量,存储在数据段的BSS区域,值默认为0
int g_var2 = 20; // 初始化的全局变量,存储在数据段的data区域,初始化值20

int main(int argc, char **argv) {
    static int s_var1;    // 未初始化的静态变量,存储在数据段的BSS区域,默认值为0
    static int s_var2=10; // 初始化的静态变量,存储在数据段的data区域,初始化值10

    // 初始化的局部变量,存储在栈中。"Hello "字符串常量被存储在RODATA区域中
    char *str="Hello"; 
    
    // 未初始化的局部变量,存储在栈中。其值是一个随机值,此时ptr称为 "野指针"
    char *ptr; 
    
    // 从堆中分配100字节的内存空间,并将内存空间的第一个地址返回给ptr保存
    ptr = malloc(100); 

    printf("[cmd args]: argv address: %p\n", argv);
    printf("\n");
    printf("[stack]: str address: %p\n", &str);
    printf("[ stack]: ptr address: %p\n", &ptr);
    printf("\n");
    printf("[heap]: malloc address: %p\n", ptr);
    printf("\n");
    printf("[bss]: s_var1 address: %p value: %d\n", &s_var1, g_var1);
    printf("[bss]: g_var1 address: %p value: %d\n", &g_var1, g_var1);
    printf("[data]: g_var2 address: %p value: %d\n", &g_var2, g_var2);
    printf("[data]: s_var2 address: %p value: %d\n", &s_var2, s_var2);
    printf("[rodata]: \"%s\" address: %p \n", str, str);
    printf("\n");
    printf("[text]: main() address: %p\n", main);
    printf("\n");
    free(ptr);
    return 0;
}

关注公众号:编程之路从0到1

编程之路从0到1

评论

公众号:编程之路从0到1

公众号

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×