程序内存到底分几个段?一篇文章讲清楚

发布时间:2026/8/22 17:59:33
程序内存到底分几个段?一篇文章讲清楚 很多初学者都听过代码段、数据段、堆、栈这些词但总是分不清。今天我们用最简单的话和一张图把程序运行后的内存分段讲明白。一、先记住这张图高地址 ---------------------- | 栈 stack | 向下增长 ---------------------- | ... | ---------------------- | 堆 heap | 向上增长 ---------------------- | BSS段 .bss | 未初始化/0 的全局和静态变量 ---------------------- | 数据段 .data | 已初始化的全局和静态变量 ---------------------- | 只读数据段 .rodata | 常量、字符串字面量 ---------------------- | 代码段 .text | 机器指令 ---------------------- 低地址这张图基本就是一个程序运行后内存里主要分区的样子。二、每个段是干什么的1. 代码段.text存放 CPU 要执行的机器指令。特点只读防止程序运行中修改自己的指令。多个进程可以共享同一份代码段节省内存。2. 只读数据段.rodata存放常量、字符串字面量比如hello world。特点只读修改会导致段错误。例如char *p abc;中的abc就在这里。3. 数据段.data存放已经初始化的全局变量和静态变量。特点可读写。程序加载时这些变量的初始值会从可执行文件拷贝到内存。4. BSS 段.bss存放未初始化或者初始化为 0 的全局变量和静态变量。特点不占可执行文件空间只在程序加载时统一清零。例如int a;作为全局变量就放在 BSS 段。5. 堆heap动态分配内存的区域比如malloc/free、new/delete。特点向上增长。需要手动管理忘记释放会造成内存泄漏。6. 栈stack存放函数局部变量、函数参数、返回地址等。特点向下增长。函数调用自动分配函数返回自动释放。递归太深可能导致栈溢出。三、用一段代码看变量在哪#includestdio.h#includestdlib.hintg_init1;// .data已初始化全局变量intg_uninit;// .bss未初始化全局变量constchar*g_strhi;// g_str 在 .data字符串 hi 在 .rodataintmain(){staticints_uninit;// .bss未初始化静态局部变量staticints_init2;// .data已初始化静态局部变量intlocal3;// 栈局部变量char*p(char*)malloc(10);// p 在栈malloc 分配的内存在堆free(p);return0;}四、总结表格段名存放内容特点管理方式代码段 .text机器指令只读、可共享操作系统加载只读数据段 .rodata常量、字符串字面量只读操作系统加载数据段 .data已初始化全局/静态变量可读写操作系统加载BSS 段 .bss未初始化或 0 的全局/静态变量加载时清零操作系统加载堆 heapmalloc/new 动态分配的内存向上增长手动管理栈 stack局部变量、函数调用信息向下增长、自动释放编译器/OS 自动管理五、最后说两句理解程序内存分段能帮你更好地理解为什么修改字符串常量会崩溃为什么递归太深会栈溢出为什么 malloc 后忘记 free 会内存泄漏不同操作系统、编译器可能有细微差异但核心思想是一致的。希望这篇文章能帮你把“段”这个概念彻底理顺。