C++内存分区(虚拟地址空间,低地址 → 高地址)
注意:C++本身标准没有规定分区,我们说的是 Linux / Android 下进程虚拟内存布局。
顺序:低地址 → 高地址
代码段(.text)
只读常量段(.rodata)
数据段(.data)
BSS段(.bss)
堆(heap)
mmap映射区
栈(stack)
内核空间(用户态不可访问)
每一块存放内容、属性
.text 代码段
存放编译后的机器指令(函数代码),只读、可共享。
main、自定义函数、库函数指令都在这里。
.rodata 只读数据段(C++重点,很多教材单独拿出来)
只读:字符串字面量、const全局常量。
const char *p = "hello"; // "hello" 在rodata
不能修改,修改触发段错误;const局部变量不在这,在栈上!
.data 初始化数据段
初始化非0的全局变量、static静态变量,可读可写
int g_a = 100;
static int s_a = 10;
.bss 未初始化数据段
未初始化 / 初始值为0 的全局、static静态变量。
程序加载时操作系统统一清零;ELF文件中不占用bin体积。
int g_b;
static int s_b = 0;
✅ data + bss = 全局静态区
堆 heap
malloc / new 分配,向高地址增长
手动申请、手动释放;不释放造成内存泄漏。
大块内存malloc会走下面mmap
mmap内存映射区
动态库(.so)、文件映射、匿名映射;Android Camera HAL、vendor库都映射在这里。
栈 stack
局部变量、函数参数、返回地址、栈帧;向低地址增长
自动管理,函数调用结束自动回收;容量很小,容易栈溢出。
⚠️ 栈上的const int a=10只是变量只读,内存可写,只是编译器不让改,和rodata不是一回事。
最上方:内核空间,用户代码无法直接访问
✅ C++特有重点(和C对比)
static局部变量:不在栈!在data/bss,只初始化一次,生命周期全程。
void func(){
static int x = 5; // .data
int y = 5; // 栈
}
类里面:
普通成员变量:跟着对象走;对象new出来 → 在堆;局部对象 → 在栈
static成员变量:全局静态区(data/bss),不属于某个对象
成员函数代码:全部放在 .text
虚函数表 vtable:一般放在 rodata(只读段);虚指针vptr跟着对象(堆/栈)
📌 容易混淆区分表
变量位置函数本身、类成员函数.text字符串字面量、全局const常量.rodata初始化非0全局/static.data零初始化/未初始化全局/static.bssnew/malloc出来对象堆普通局部变量、局部对象、函数形参栈static局部变量.data/.bss📖 背诵精简版(面试口述)
C++进程虚拟内存从低到高:代码段、只读段rodata、data段、bss段、堆、mmap区、栈。
堆向高地址增长,栈向低地址增长;static变量在静态区,局部变量在栈,new在堆,字符串常量在rodata。
❓ 坑
不要把C++的内存五大区旧说法(栈、堆、全局静态区、常量区、代码区)和ELF段混起来,两种说法都对:
简化五大区(很多C++教材):代码区、常量区、全局静态区、堆、栈
ELF细分:text、rodata、data、bss、heap、mmap、stack