目录
前言
什么是 .data 段(运行时视角)
什么是 .bss 段(运行时视角)
.data 与 .bss 对比
static 局部变量落在哪个段
磁盘 ELF 段 和 进程内存段的区别
.data/.bss 的生命周期与释放时机
.data/.bss 总结
前言
AI问答式记录,比较详细
什么是 .data 段(运行时视角)
.data属于进程静态存储区,位于进程虚拟地址空间内。
✅进入.data的两个必要条件,必须同时满足
- 变量:全局变量 或者
static静态变量 - 初始化:显式赋值非 0 的初始值
🟡重点提醒 函数内部普通局部变量开辟在栈帧,永远不会进入
.data。
表格
| 对比项 | .data 段 |
|---|---|
| 内存归属 | 静态存储区(虚拟内存) |
| 可存放变量 | 全局、static,初值不为 0 |
| 内存权限 | 可读、可写、不可执行 |
| 磁盘 ELF 行为 | 保存变量初始数据,占用磁盘空间 |
c
int g_a = 100; // 全局,非0初值 → .data static int s_b = 200; // static,非0初值 → .data void func() { int l_c = 10; // 局部变量 → 栈 }📝自测
static int num = 60;该变量存放在哪个段?
- .data 的变量数据是怎么来到内存中的?
- 函数中普通局部变量会不会存放在
.data?
:
1.data
2. 映射虚拟内存
3.不会
:
✅批改
.data正确- 不完全准确:磁盘 ELF 文件保存着初始数值,程序加载时把磁盘上的数据拷贝到内存,不只是单纯映射虚拟内存。虚拟地址只是地址,真实数据来源于可执行文件。
- 不会 正确,局部变量在栈帧。
什么是 .bss 段(运行时视角)
.bss同样属于进程静态存储区,处在虚拟地址空间。
✅进入.bss的两个必要条件,必须同时满足
- 变量:全局变量 或者
static静态变量 - 初始化:不写初始化,或者显式赋值为 0
🟡重点提醒 函数内部普通局部变量开辟在栈帧,永远不会进入
.bss。
表格
| 对比项 | .bss 段 |
|---|---|
| 内存归属 | 静态存储区(虚拟内存) |
| 可存放变量 | 全局、static,未初始化 / 初值等于 0 |
| 内存权限 | 可读、可写、不可执行 |
| 磁盘 ELF 行为 | 不存储变量有效数据,几乎不占用磁盘空间 |
c
int g_x; // 全局未初始化 → .bss static int s_y = 0; // static显式赋值0 → .bss void func() { int l_z; // 局部变量 → 栈 }📝自测
static int val = 0;该变量存放在哪个段?- .bss 段在 ELF 磁盘文件中保存变量的实际数值吗?
- 函数内部普通局部变量会不会存放在
.bss?
:
1.bss
2.不会
3.不会
:
✅批改
.bss正确- 不会 正确,
.bss不在 ELF 中存放实际数值,仅记录需要多大内存 - 不会 正确,局部变量在栈帧
🟡小结
.bss只记录内存大小信息,磁盘几乎不占空间;程序加载后操作系统把这一块内存整体清零。
.data 与 .bss 对比
二者都属于静态存储区,位于进程虚拟地址空间。局部变量存栈,和这两个段无关。
表格
| 对比项目 | .data | .bss |
|---|---|---|
| 接收变量 | 全局 /static,初值非 0 | 全局 /static,未初始化 或初值 = 0 |
| ELF 磁盘文件 | 保存变量初始值,占用磁盘空间 | 仅记录内存大小,不存真实数值,几乎不占磁盘 |
| 内存数据来源 | 把磁盘的数据拷贝到内存 | 操作系统加载后整块内存置 0 |
| 内存权限 | 可读、可写、不可执行 | 可读、可写、不可执行 |
🟡高频易错点
int g = 0;,就算手动写赋值 0,依然归属于.bss,不属于.data。
c
int a = 10; // .data static int b; // .bss int c = 0; // .bss void test() { int d = 5; // 栈 }📝自测
int global = 0;该全局变量属于哪一个段?- 下列哪一项是
.data的特点: A、磁盘不保存数据 B、从 ELF 拷贝初值到内存 C、用来存放栈变量 - 判断:局部 static 变量有可能落到 .bss 或者 .data(对 / 错)
:
1.dss
2.B
3.对
:
✅批改
- 笔误,是.bss,结论正确。
int global = 0;初值为 0,进入.bss - B 正确,
.data会将 ELF 里面保存的初值拷贝进内存 - 对 正确。局部
static本质是静态变量:初值非 0 进.data;初值为 0 / 不初始化进.bss
🟡小结
static修饰的局部变量,不在栈上,放到静态存储区(.data/.bss),函数结束不会销毁。
static 局部变量落在哪个段
普通局部变量在栈帧,函数调用结束栈回收,变量直接销毁。 被static修饰的局部变量,不再存放在栈中,放到静态存储区。
✅分配规则
- static 局部变量,显式非 0 初始化 →.data 段
- static 局部变量,不初始化 / 初始化为 0 →.bss 段
🟡重点
- 生命周期:随整个进程,函数退出不会销毁,保留上一次的值
- 作用域:依旧只能在定义它的函数内部使用,别的函数不能直接访问
表格
| 变量类型 | 存储位置 | 生命周期 |
|---|---|---|
| 普通局部变量 | 栈帧 | 函数调用期间 |
| static 局部变量 | .data / .bss | 整个进程运行周期 |
c
void func(void) { static int s1 = 10; //非0初值 → .data static int s2 = 0; //初值0 → .bss static int s3; //未初始化 → .bss int normal; //普通局部 → 栈 }📝自测
static int a = 5;写在函数内部,该变量存放在哪个段?- static 局部变量,函数调用结束之后,变量会销毁吗?
- 判断:static 局部变量别的函数可以直接访问(对 / 错)
:
1. data
2.不会
3.错
:
✅批改
.data正确,非 0 初始化的 static 局部变量存放在.data 段- 不会 正确,存放在静态存储区,进程结束才销毁,函数退出会保留数值
- 错 正确,作用域仅限于当前函数,外部函数不能直接访问
🟡小结 static 局部变量:存储位置在静态区,作用域局限于函数内,这是最容易混淆的考点。
磁盘 ELF 段 和 进程内存段的区别
写好的 C 程序编译链接之后得到ELF 可执行文件,存放在磁盘。 当程序运行,操作系统把 ELF 加载,才形成进程的虚拟地址空间。
🟡关键区分
- 磁盘:是文件,存在硬盘上
- 进程虚拟内存:程序跑起来之后,操作系统给进程分配的虚拟地址空间
表格
| 对象 | .data | .bss |
|---|---|---|
| 磁盘 ELF 文件 | 占用磁盘,存放变量初始值 | 几乎不占磁盘,只记录需要的内存大小 |
| 运行之后内存 | 映射到虚拟内存,数据从 ELF 拷贝过来 | 虚拟内存分配空间,操作系统置 0 |
⚠️非常容易踩坑:.bss在磁盘里根本没有存放变量数据,只有程序运行起来之后,内存才会有这一块空间。
c
int g_val1 = 20; //磁盘.data段保存20,运行加载到内存.data int g_val2; //磁盘不存数值,仅记录大小,运行分配到内存.bss并清零📝自测
- ELF 磁盘文件中,
.bss是否存储变量实际的值? .data段变量初始值来自哪里?- 判断:.bss 拥有磁盘文件存储空间(对 / 错)
:
1.否
2.EIF文件
3.错
:
✅批改
- 否 正确,磁盘 ELF 的.bss 只记录内存尺寸,不存变量真实数值
- ELF 文件 正确,程序加载时把 ELF 里保存的初值拷贝进内存
- 错 正确,
.bss不占用 ELF 有效存储空间
🟡小结 磁盘上 ELF 的段 ≠ 运行时内存段。.bss 属于 “运行时才创造出来” 的内存空间,磁盘文件不给它存数据。
.data/.bss 的生命周期与释放时机
.data、.bss的变量全部属于静态存储区。
- 分配时机:程序加载运行的时候,操作系统就为它们分配虚拟内存。
- 生命周期:贯穿整个进程的全部运行时间。
- 释放时机:进程结束退出操作系统回收内存。函数调用、函数返回,不会回收这两块内存。
🟡区分对比 普通局部变量(栈):函数调用开辟,函数结束立刻回收。 .data/.bss 变量:不受函数进出影响。
表格
| .data / .bss | 栈局部变量 | |
|---|---|---|
| 分配 | 程序加载时 | 函数调用时 |
| 释放 | 进程结束 | 函数执行完毕 |
| 生存时间 | 整个进程 | 单次函数调用 |
c
void count(void) { static int cnt = 0; // .bss,函数退出不会销毁,数值保留 cnt++; } int g = 10; // .data,全程存活📝自测
- .data、.bss 中变量什么时候释放内存?
- 函数返回之后,static 静态变量的值会丢失吗?
- 判断:进入函数才分配.data 段变量的内存(对 / 错)
:
1.程序结束
2.不会
3.错
:
✅批改
- 程序结束 正确,进程退出操作系统回收
.data/.bss的内存 - 不会 正确,static 变量存静态存储区,函数返回值保留
- 错 正确,程序加载的时候就完成内存分配,不是调用函数才分配
🟡小结 栈随函数生灭;
.data、.bss跟随整个进程,和函数调用无关。
.data/.bss 总结
什么样的变量才会进.data/.bss只有全局变量、static 修饰变量。普通局部变量在栈,跟这两个段无关。
归属判定规则
- 全局 /static,显式非 0 初始化 →
.data - 全局 /static,未初始化 或者初始化为 0 →
.bss
- 磁盘 ELF 与内存差异
.data:ELF 磁盘保存初始值,程序加载拷贝到内存。.bss:磁盘上不存放数据,仅记录需要内存大小;运行时分配虚拟内存,操作系统统一清零。
- 生命周期都属于静态存储区,程序加载就分配内存,进程结束才释放,不受函数调用‑返回影响。
c
int A = 10; // .data int B = 0; // .bss int C; // .bss void test(){ static int D = 20; // .data static int E = 0; // .bss int F; // 栈 }