C/C++内存模型

C语言编程中的内存基本模型

C的内存基本上分为4部分:静态存储区、堆区、栈区以及常量区。他们的功能不同,对它们使用方式也就不同。

  1. 栈 ——由编译器自动分配释放。

  2. 堆 ——一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。

  3. 全局区(静态区)——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(data段),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(bss段)( C++中已经不再这样划分),程序结束释放。

  4. 另外还有一个专门放常量的地方,程序结束释放:

  • 函数体中定义的变量通常是在栈上;
  • 用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上;
  • 在所有函数体外定义的是全局量;
  • 加了static修饰符后不管在哪里都存放在全局区(静态区);
  • 在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用;
  • 在函数体内定义的static表示只在该函数体内有效;
  • 另外,函数中的"adgfdf"这样的字符串存放在常量区。

一个正在运行着的C编译程序占用的内存分为5个部分:代码区、初始化数据区、未初始化数据区、堆区 和栈区。

C++编程中的内存基本模型

在C++中内存分成5个区,分别是堆、栈、全局/静态存储区、常量存储区和代码区;

  1. 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区,里面的变量通常是局部变量、函数参数等。

  2. 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收

  3. 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

  4. 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。

  5. 代码区 ( .text段),存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。

  1. .text
    代码区(code section)。由编译器链接器生成的可执行指令,程序执行时由加载器(loader)从可执行文件拷贝到内存中。为了安全考虑,防止别的区域更改代码区数据(即可执行指令),代码区具有只读属性。另一个方面,代码区通常具有可共享性(sharable),即在内存中只有一份代码区,如编译器,假如同时有多个编译任务在执行,这些编译任务会共享编译器的代码区,但同时各个编译任务又有自己独立的区域。
  2. rodata
    只读数据区(read-only section)。包含:只读全局变量,只读字符串变量,只读静态(static)变量。程序执行时由加载器loader)从可执行文件拷贝到内存中。
  3. data
    可写数据区(RW section)。包括:可写全局变量,可写静态(static)变量。程序执行时由加载器(loader)从可执行文件拷贝到内存中。
  4. bss
    未初始化数据区(un-initialized section)。包括:未初始化或初始化为零的全局变量,未初始化或初始化为零的静态(static)变量。为了减小可执行文件的大小,在可执行文件中bss区只是一个占位符。在程序执行时,加载器(loader)根据bss区的大小,在内存中开辟相应空间,同时将这些内存空间全部初始化为零。
    .text, .rodata, .data, .bss四个区域,统称为编译时内存(compiler-time memory),顾名思义,这些区域的大小在编译时就可以决定。
  5. heap
    堆区。对于C语言而言,heap指程序运行时(run-time)由malloc, calloc, realloc等函数分配的内存。
  6. stack
    栈区。每一次函数调用,都会发生一次压栈操作,被压栈数据称为一个栈帧(stack frame),有多少次函数调用(包括main()函数),栈区就有多少个栈帧。相应的,每一次函数调用返回,都会相应的发生一次出栈操作,栈帧就会减少一个。
    函数调用时,根据压栈的顺序,依次需要压栈的数据包括:调用函数(caller funtion)的上下文环境(context environment),如寄存器;函数返回地址;被调用函数(called funtion)的参数列表;被调用函数的非静态(static)局部变量。
    当栈区溢出(stack overflow/underflow)时,栈区数据被污染,程序执行错误,甚至“跑飞"(函数返回地址被修改)。
posted @ 2023-02-19 17:18  小满的博客  阅读(2)  评论(0编辑  收藏  举报