C++程序在执行时,将内存大方向划分位4个区域
- 代码区: 存放函数体的二进制代码,由操作系统进行管理的
- 全局区: 存放全局变量和静态变量以及常量
- 栈区: 由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区: 由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
意义: 不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
程序运行前 {#程序运行前}
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:
代码区 {#代码区}
存放CPU执行的机器指令
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区 {#全局区}
全局变量、静态变量字符串常量和其他常量存放在此 该区域的数据在程序结束后由操作系统释放
|---------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| // 全局变量 int g_a = 10; int g_b = 10; // 全局常量 const int c_g_a = 10; const int c_g_b = 10; int main() { // 局部变量 int a = 10; int b = 10; // 打印地址 cout << "局部变量a地址为:" << (int)&a << endl; cout << "局部变量b地址为:" << (int)&b << endl; cout << "全局变量g_a地址为:" << (int)&g_a << endl; cout << "全局变量g_b地址为:" << (int)&g_b << endl; // 静态变量 static int s_a = 10; static int s_b = 10; cout << "静态变量s_a地址为:" << (int)&s_a << endl; cout << "静态变量s_b地址为:" << (int)&s_b << endl; cout << "字符串常量地址为:" << (int)&"hello world" << endl; cout << "字符串常量地址为:" << (int)&"hello world1" << endl; cout << "全局常量c_g_a地址为:" << (int)&c_g_a << endl; cout << "全局常量c_g_b地址为:" << (int)&c_g_b << endl; const int c_l_a = 10; const int c_l_b = 10; cout << "局部常量c_l_a地址为:" << (int)&c_l_a << endl; cout << "局部常量c_l_b地址为:" << (int)&c_l_b << endl; system("pause"); return 0; }
|
x64(64位):
x86(32位):
Q: 为什么当vs管理器为x64(64位)时,a的地址比b小32,但是管理器改为x86(32位)时,a比b地址大12
- x64架构(64位)
- 栈对齐:x64架构通常要求栈对齐到16字节或32字节边界,以优化性能并满足某些指令集的要求。这可能导致在局部变量之间插入额外的填充(padding)。
- 调用约定:在x64架构下,函数调用时可能需要在栈上保留更多的空间用于寄存器保存区域(callee-saved registers)和其他目的。这可能导致局部变量之间的地址差异大于它们的大小。
- 优化:编译器可能会在64位模式下执行更积极的优化,这可能会影响变量的布局。
- 局部变量大小 :即使局部变量是
int
类型,它们在栈上的布局也可能会受到其他因素的影响,如调用约定、栈对齐等。
在x64架构下,32字节的差异可能是由于编译器在a
和b
之间插入了对齐填充,或者由于其他局部变量或保留空间的布局。
- x86架构(32位)
- 栈对齐:x86架构通常要求栈对齐到4字节边界,这意味着局部变量之间的地址差异通常是它们大小的整数倍。
- 调用约定:在x86架构下,函数调用时在栈上保留的空间通常比x64架构少,因此局部变量之间的地址差异可能更小。
- 优化 :编译器在32位模式下的优化可能与64位模式不同,这可能会影响变量的布局。
在x86架构下,12字节的差异可能是因为:- 在
a
和b
之间可能有其他局部变量或对齐填充。 - 编译器可能为了保持栈对齐而插入填充。
- 由于某些优化,编译器可能改变了局部变量的顺序或布局。
- 在
程序运行前 {#程序运行前-1}
栈区 {#栈区}
由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
示例:
|---------------------|---------|
| 1 2 3 4 5 6
| |