目录
任何的编程语言都会产生两种东西:指令和数据。
C++代码编译连接后会产生一个.exe可执行文件,放在磁盘上。CPU不可能直接运行磁盘上的程序。CPU首先把程序从磁盘上加载到内存中,那么它把可执行程序的哪些东西加载到内存当中,加载到内存当中如何存放?内存有没有区域的划分,划分了以后是什么样子?
以x86 32位linux环境为例,当一个程序运行时,linux系统内核会给进程开辟一个2的32位,也就是4G大小的虚拟地址空间,默认被划分为两个部分:
用户空间3G,内核空间1G(可以通过修改系统的配置,来调整内存比例)
用户空间:
不能访问段:
- 并没有从0地址开始存放内容,前面空了一段(0~0x08048000),是预留的不能访问。
- 无效地址段,提供了一个物理内存和虚拟内存之间的间隔,防止进程访问不属于它的内存区域。
代码段(.text段)和只读数据段(.rodata):
指令运行时放在代码段/.text段
char *p = “hello world”
指针p在栈上,“hello world”字符串在.rodata只读数据段
.text 和 .rodata只能读,不能写。
.data段:
放的是数据,已经初始化的,而且初始化不为0的数据;
已经初始化的全局变量,静态变量,常量。
.bss段:
- 未初始化的全局变量和静态局部变量
- 初始值为0的全局变量和静态局部变量(依赖于编译器实现)
- 未定义且初值不为0的符号(该初值即common block的大小)
我们在全局的作用域上去写全局变量,没有初始化,我们去打印它的值,是0,因为存放在.bss段,程序运行时,内核给当前进程分配内存空间,将未初始化的数据放在.bss段,内核将.bss段数据全部置为0;
.heap堆:
- .heap堆(这是个空洞,程序运行以后在调用new或者malloc的时候,才会在这里分配堆内存)(从上到下,即低地址到高地址分配)
- 堆地址是不连续的,他是系统将空闲内存块连接起来的链表,用户用new/malloc请求分配时,找到第一个满足大小要求的块从链表中删除此节点,然后分给用户,没有栈内存速度快,但是很灵活。
加载共享库(动态链接库):
windows下是:.dll linux下是:.so
stack空间:
- stack空间(函数运行或者产生线程池,每个线程独有的栈空间)
- 局部变量存放在栈上
- 栈从高地址到低地址,从下往上增长
- 栈内存区的地址是连续的,由系统控制速度较快
命令行参数和环境变量:
存储命令行参数和环境变量用于传递和存储进程运行时的配置信息和环境参数。
内核空间:
内核空间主要分为了3个区域:
- DMA—16M
- NORMAL—800多M(存进程内核空间PCB块,进程控制块,内核空间的线程,内核函数在运行时所依赖的栈空间)
- HIGHMEM----高端内存,做地址映射