请思考当以下这个经典的hello world代码,调入内存并且在cpu上运行变成一个进程的时候,代码中的各个数据在内存中是如何进行分布的
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
进程内存布局
进程在内存中的数据分布通常分为多个段(Segment),每个段负责存储不同类型的数据。以下是典型的进程内存布局:
1. 代码段(Text Segment)
内容:存储程序的机器指令(即编译后的代码)。
特性:只读,不可修改,多个进程可共享同一代码段。
2. 数据段(Data Segment)
内容:存储全局变量和静态变量。
分类:
已初始化数据段:存储显式初始化的全局和静态变量。
未初始化数据段(BSS段):存储未初始化的全局和静态变量,程序加载时初始化为零。
3. 堆(Heap)
内容:动态分配的内存(如
malloc
、new
等)。特性:手动管理,大小不固定,向高地址增长。
4. 栈(Stack)
内容:存储局部变量、函数参数、返回地址等。
特性:自动管理,大小有限,向低地址增长。
5. 共享库(Shared Libraries)
内容:存储动态链接库的代码和数据。
特性:多个进程可共享,减少内存占用。
6. 环境变量和命令行参数
内容:存储环境变量和命令行参数。
位置:通常位于栈的上方。
7. 内存映射区(Memory Mapped Region)
内容:用于内存映射文件或匿名映射。
特性:允许文件直接映射到内存,便于高效访问。
典型内存布局(从低到高地址)
+---------------------------+ 高地址
| 环境变量和命令行参数 |
+---------------------------+
| 栈(Stack) | <--- 向低地址增长
| | |
| | |
| v |
+---------------------------+
| 内存映射区 |
+---------------------------+
| 共享库 |
+---------------------------+
| ^ |
| | |
| | |
| 堆(Heap) | <--- 向高地址增长
+---------------------------+
| 未初始化数据段(BSS) |
+---------------------------+
| 已初始化数据段(Data) |
+---------------------------+
| 代码段(Text) |
+---------------------------+ 低地址
Hello world在内存中的分布
#include <stdio.h>
int main() {
int i = 42;
printf("Hello, World!\n");
printf("int i = %d\n", i);
return 0;
}
+---------------------------+ 高地址
| 环境变量和命令行参数 |
+---------------------------+
| 栈(Stack) | <--- 向低地址增长
| - main函数的栈帧 |
| - 局部变量 int i = 42 |
| - printf的参数 |
| - "Hello, World!\n" |
| - "int i = %d\n", i |
+---------------------------+
| 共享库(Shared Libraries) |
| - printf的实现代码 |
+---------------------------+
| 堆(Heap) | <--- 向高地址增长
| (该程序未使用堆) |
+---------------------------+
| 未初始化数据段(BSS) |
| (该程序未使用BSS) |
+---------------------------+
| 已初始化数据段(Data) |
| (该程序未使用数据段) |
+---------------------------+
| 代码段(Text) |
| - main函数的机器指令 |
| - printf的调用指令 |
+---------------------------+ 低地址