当前位置:首页>Linux>Linux菜鸟专题:程序五大内存分区

Linux菜鸟专题:程序五大内存分区

  • 2026-10-11 05:52:24
Linux菜鸟专题:程序五大内存分区

    一个典型的C程序在内存中(特指虚拟内存空间)会被划分为以下几个关键区域,从低地址到高地址大致如下:完整分为:代码段(.text)、只读常量段(.rodata)、全局数据段(.data/.bss)、堆(heap)、栈(stack)。

    注意,一个进程只对应一套五大内存分区。函数再多、嵌套再深,只是在唯一的栈里折腾,不会多开一套内存分区。五大内存分区结构体如下图所示:

    在我们实际代码开发中,其实是很难把上面的所有概念和写的代码联系起来,本文将通过最简单的示例代码来说明内存的五大分区。

#include<stdio.h>#include<stdlib.h>// 1. 全局初始化变量 → .data 全局数据段int g_init = 10;// 2. 全局未初始化变量 → .bss 全局零初始化段int g_uninit;// 3. 字符串字面量 → .rodata 只读常量段const char* g_str = "hello world";voidfunc(){    // 4. 普通局部变量 → 栈 stack    int local_a = 20;    // 5. static局部变量(初始化)→ .data    static int s_init = 5;    // 6. static局部变量(未初始化)→ .bss    static int s_uninit;    // 7. malloc分配内存 → 堆 heap    int* p_heap = malloc(sizeof(int));    *p_heap = 99;    return;}intmain(){    func();    return 0;}

代码段 .text

    专门存放程序编译后所有的二进制机器指令,不存任何变量数据。上面代码里的 main函数、func函数的所有执行逻辑,比如变量赋值、函数调用、malloc申请内存、return 返回等代码,编译后全部变成机器指令存放在代码段。本段权限只读、可执行,程序运行过程中绝对不会被修改,生命周期跟随整个进程,程序启动加载、程序结束才释放。无论程序有多少个函数、多少层嵌套,所有执行指令全部统一在这一个代码段内,不会新开空间。

只读常量段 .rodata

    专门存放程序中固定不变的只读内容,核心就是字符串字面量和全局const常量。对应案例中 "hello world" 这个字符串本体就存放在当前段,而指针变量 g_str 只是存储了这个字符串的内存地址。本段内存权限严格只读,代码里如果强行修改字符串内容,会直接触发段错误、程序崩溃。数据生命周期全程常驻内存,不会随函数调用结束而消失。

全局数据区(.data + .bss 统一区域)

    所有全局变量、static静态变量,不管是全局还是函数内部定义的,全部统一存放在全局数据区,不在栈上、函数结束不会销毁,全程常驻进程内存。其中 .data 段存放已经初始化的全局和静态变量,对应案例里的 int g_init = 10、static int s_init = 5,程序加载时就会把初始值写入内存,占用程序文件体积。 而 .bss 段存放只声明、未初始化的全局和静态变量,对应案例里的 int g_uninit、static int s_uninit,本段特点是不占用程序文件大小,程序启动后系统会统一自动清零,是面试高频考点。

static 和 const 有啥区别?const:值禁止修改 → 进只读区static:生命周期变长、值可以随便改 → 进全局数据区

栈 stack

    栈是程序运行最频繁的动态内存区域,专门存放普通局部变量、函数参数、函数返回地址、栈帧信息。案例中 func 函数内部的 int local_a = 20、指针变量 int* p_heap 都是典型的栈变量。栈完全由系统硬件自动管理,函数调用时自动开辟栈帧分配内存,函数执行结束立刻自动销毁回收,完全不用手动操作。栈空间很小,默认只有几MB,递归过深、定义超大局部数组都会造成栈溢出。每一次函数调用都是在当前进程唯一的栈空间内压栈、出栈,不会单独新开内存分区。

堆 heap

    堆是唯一需要程序员手动管理的内存区域,专门存放 malloc、calloc、realloc 动态申请的内存。案例中 malloc(sizeof(int)) 开辟的内存、赋值的数值 99 全部存放在堆空间,而保存地址的指针变量 p_heap 本身在栈上。堆的生命周期完全由开发者掌控,malloc 申请后必须手动 free 释放,只申请不释放会造成内存泄漏,重复释放会导致程序崩溃。堆空间容量极大,适合存放大数据,进程运行期间不会自动回收,只有手动释放或程序结束系统才会收回内存。

分区

存放内容

生命周期

是否手动管理

.text 代码段

所有函数二进制指令

程序运行全程

不用管

.rodata 只读段

字符串常量、const全局常量

程序运行全程,只读不可改

不用管

.data 全局数据段

已初始化全局/static静态变量

程序运行全程

不用管

.bss 零段

未初始化全局/static静态变量

程序运行全程,启动自动清零

不用管

stack 栈

普通局部变量、函数参数、返回地址

当前函数内有效,退出自动销毁

硬件自动管理

heap 堆

malloc 动态申请的内存

malloc → free之间有效

程序员手动管理

高频易错点总结:

  1. 普通局部变量 → 栈;static局部变量 → 全局数据段,二者完全分开;

  2. 指针变量本身永远在栈/全局区;指针指向的数据,看来源:字符串常量在.rodata,malloc数据在堆;

  3. 栈自动释放,堆必须手动free,全局数据段程序结束才释放;

  4. 代码段只存指令,不存任何变量。

最新文章

随机文章