当把一个可执行文件加载到内存后,就变成了一个进程。这个虚拟空间(内存)大概分成以下几部分:
1. 栈(堆栈/栈区)
- 描述:栈区用于存放局部变量、函数参数、返回地址等。栈是由高地址向低地址增长的。
- 特点:栈的内存分配是由编译器自动完成的,速度较快,但分配的内存空间较小。
2. 堆(堆区)
- 描述:堆区用于动态分配内存,如通过
new
、malloc
等函数申请的内存空间。堆是由低地址向高地址增长的。 - 特点:堆的内存分配由程序员手动管理,灵活性高,但容易产生内存泄漏和碎片化问题。
3. BSS段
- 描述:BSS段用于存放未初始化的全局变量和静态变量,以及初始化为0的全局变量和静态变量。
- 特点:BSS段在程序加载时会被操作系统清零,因此这些变量在程序开始执行时默认值为0。
4. 数据段
- 描述:数据段用于存放已初始化的全局变量和静态变量。
- 特点:数据段在程序加载时会被操作系统初始化为指定的值。
5. 代码段
- 描述:代码段用于存放程序的执行代码,即编译后的机器指令。
- 特点:代码段通常是只读的,以防止程序意外修改指令。代码段可以被多个进程共享。
进程内存空间布局示意图
+--------------------+ 高地址
| 栈区(Stack) |
|--------------------|
| 堆区(Heap) |
|--------------------|
| BSS段(BSS Segment)|
|-------------------- |
| 数据段(Data Segment)|
|--------------------|
| 代码段(Code Segment)|
+--------------------+ 低地址
可执行文件的内存布局
在可执行文件没有加载到内存时,它的布局也分为多个部分,如数据段、BSS段等。以下是一个典型的可执行文件的内存布局:
- 代码段:存放程序的机器指令。
- 数据段:存放已初始化的全局变量和静态变量。
- BSS段:存放未初始化的全局变量和静态变量。
- 符号表:存放符号信息,如变量名、函数名等,用于调试和链接。
- 字符串表:存放字符串常量。
示例代码
以下是一个简单的示例代码,展示了不同内存区域的变量:
#include <iostream>
#include <cstdlib>
// 全局变量
int global_var = 10; // 数据段
int uninitialized_global_var; // BSS段
int main() {
// 局部变量
int local_var = 20; // 栈区
// 动态分配内存
int* heap_var = (int*)malloc(sizeof(int)); // 堆区
*heap_var = 30;
std::cout << "Address of code (main): " << (void*)main << std::endl;
std::cout << "Address of global_var: " << &global_var << std::endl;
std::cout << "Address of uninitialized_global_var: " << &uninitialized_global_var << std::endl;
std::cout << "Address of local_var: " << &local_var << std::endl;
std::cout << "Address of heap_var: " << heap_var << std::endl;
free(heap_var); // 释放动态分配的内存
return 0;
}
运行结果(地址可能因系统和编译器不同而有所不同):
Address of code (main): 0x401560
Address of global_var: 0x404010
Address of uninitialized_global_var: 0x408030
Address of local_var: 0x71fe44
Address of heap_var: 0x1c0068e0
在上面的代码中:
global_var
是一个全局变量,存储在数据段。uninitialized_global_var
是一个未初始化的全局变量,存储在 BSS 段。local_var
是一个局部变量,存储在栈区。heap_var
是通过malloc
动态分配的内存,存储在堆区。main
函数的地址代表了代码段。
通过这个示例,可以看到不同类型的变量在内存中的地址分布,帮助理解进程内存空间的布局。