任何的编程语言编译所产生的只有 指令和数据。
在Windows操作系统/Linux操作系统下,C++文件编译链接之后会产生一个.exe/.out文件,该文件存储在磁盘上。
CPU运行程序,需要将文件加载到内存中,但肯定不是直接加载到实际的物理内存中,而是加载到进程的虚拟地址空间。x86 32位Linux环境下,Linux内核会给当前进程分配一块2^32大小的空间,大小为4G。
虚拟就是:
它存在,你能看得见,它是物理的
它存在,你看不见,它是透明的
它不存在,你却看得见,它是虚拟的
它不存在,你也看不见,它被删除了
虚拟地址空间不是物理内存,本质底层就是内核所创建的一系列数据结构。
以下是进程虚拟地址空间划分图:
接下来对每一个划分部分进行说明:(用户空间)
1、 0x00000000-0x08048000:这一段是不能被访问的,如果访问,程序会奔溃。
2、.text(代码段)存放指令,.rodata只读数据段(常量区)const char *p="hello world!"。
3、.data已初始化数据段。
4、.bss已初始化数据段或已初始化为零,内核会将.bss段的数据全部置为0。
5、堆内存,使用new/malloc进行申请,从上往下。
6、加载共享库,Windows下.dll,linux下.so文件。
7、栈空间,函数运行在栈上开辟空间,每个线程私有的线程栈。从下往上进行增长。
8、例如执行指令:./a.out 192.168.1.100 9090 。该段用来存储程序运行时的命令行参数和环境变量。
#include <iostream>
int gdata1 = 10;
int gdata2= 0;
int gdata3;
static int gdata4 = 11;
static int gdata5 = 0;
static int gdata6;
int main()
{
int a = 12;
int b = 0;
int c;
static int e = 13;
static int f = 0;
static int g;
return 0;
}
所以:
gdata1、gdata4已初始化且不为零,存储在.data段。
gdata2、gdata3、gdata5、gdata6未初始化或者初始化为零,存储在.bss段。
而对于main()函数中的局部变量,有以下分析:
int a = 12; mov dword ptr[a],0Ch
int b = 0;
int c;
这三者编译生成指令,指令存放在.text段。程序运行时,指令会在栈上开辟空间用来临时存储局部变量。
而e、f、g这三个静态局部变量分别存储在.data、.bss、.bss,但是程序启动的时候并不会进行初始化,是第一次运行到的时候才进行初始化。
每个进程的用户空间是私有的,但内核空间是共享的!!!
进程与进程之间通信难是因为各个进程的用户空间是私有的,所以可以通过管道来进行通信。