【C++ 学习笔记】程序运行时的内存四区(操作系统通用规则)

内存分区

C++程序在执行时,将内存大方向划分为4个区域:

代码区:存放编译后生成的机器指令(二进制代码),由操作系统进行管理,具有只读,共享特性

全局区:存放全局变量静态变量以及常量(字符串常量、全局 const 变量等),程序生命周期内一直存在

栈区:由操作系统自动分配与释放,存放函数参数、局部变量等,随函数调用/返回自动创建/销毁

堆区:由程序员自己分配(new/malloc)和释放(free/delete),若程序员不释放,程序结束时操作系统自动回收

这样的意义在于,不同区域存放的数据,赋予不同的生命周期,更灵活的同时减少资源浪费

程序运行前

程序编译后,生成.exe可执行文件,存储在硬盘中,其内部已划分出代码段数据段等结构:

(名词解释↓)

代码段:存放编译后生成的机器指令(CPU 可直接执行的二进制代码)

数据段:存放初始化的全局变量、静态变量

BSS段:存放初始化的全局变量、静态变量 (运行时自动初始化为 0)

程序运行后

一、代码区

存放编译后生成的二进制代码

代码区是共享的、只读的。

共享的目的在于节省资源——那些频繁被执行的程序,只需要在内存中有一份代码即可

只读的目的在于防止程序运行时意外地修改其指令

PS:大部分程序都遵循内存共享,但类似于有动态修改代码需求的程序不会遵循。比如一些游戏外挂、加壳反调试软件这些

二、全局区

全局变量、静态变量(static修饰)、常量(如字符串常量、全局const变量)存放于此

特点:程序运行期间一直存在,直到程序结束才会被操作系统释放

补充一点,全局变量和局部变量在内存里基本上隔得相对较远,如下图所示

三、栈区

主要存放:函数参数、局部变量、函数返回地址

由操作系统自动分配与释放,随函数调用自动创建、函数返回自动销毁

存取速度,但空间有限,过量分配会导致栈溢出(比如无限递归)

有时候,局部变量销毁后输出结果依旧正确,这是因为 “销毁” 只是标记这块内存为空闲,数据暂时未被覆盖。但这块内存已不属于当前函数,后续若被其他内存申请覆盖,再访问就会触发未定义行为(不一定立刻报错,可能出现乱码 / 崩溃等)

(所以不要在程序里返回局部变量的地址!)

四、堆区

存放内容:程序员手动申请的动态内存

核心特性:

生命周期由程序员完全控制,若未手动释放,程序结束时会由操作系统兜底回收

空间较大,但存取速度比栈区慢,使用不当容易造成内存泄漏

你可以用new关键字手动开辟内存,new关键字会返回一个内存地址,可以用指针来接收:

int* test() { int * p =new int(10); return p; }

用完了之后别忘了delete掉!

delete p;