众所周知,任何的编程语言都会产生两种东西:数据和指令。那么拿我们c++代码来看,编译链接完成之后在我们Windows上来说会产生一个xxx.exe的可执行文件,现在这个文件放在我们磁盘上,那么cpu肯定是不能直接运行磁盘上的程序的,那么在运行它的时候首先会把这个程序从磁盘上加载到内存当中,那么就涉及到几个问题
1.这一个可执行程序的哪些东西将会加载到内存当中?
2.加载到内存当中他是如何存放的?
3.内存有没有区域的划分?
4.划分了以后到底是什么样子?
首先我们得搞清楚一点,加载到内存是不可能直接加载到物理内存里!!!
拿我们当前的学习环境为例:在x86 32位Linux环境下
当我们的程序加载到内存的时候首先Linux系统会给当前进程分配一个2^32大小的一块空间 也就是4G。这个空间我们定义为进程的虚拟地址空间那么这个虚拟我们该怎么理解了?IBM是这么解释的:
它存在,你能看的见,它是物理的;
它存在,你看不见,它是透明的;
它不存在,你却看得见,它是虚拟的;
它不存在,你也看不见,他被删除了;
但是一定要记住虚拟内存和虚拟地址空间不能记混了。
进程的虚拟地址空间:
用户空间:
1.指令都会放在.text段,只读数据段.rodata一般存放常量字符串;二者都是只能读不能写。
2. .data是专门存放初始化且不为0的数据。
3. .bss段是存放未初始化的以及初始化为0的数据。当我们在全局的作用域里面去写一个全局变量没有初始化,当我们去打印它的值得时候是一个0,这就是因为它存放在.bss段,我们的操作系统会自己负责把.bss段的数据全部置成0,所以这也就是我们为什么看到未初始化的全局变量我们去拓印它的值得时候是0的原因。
4 . 我们程序运行以后了,当我们调用了new 、malloc才会分配堆内存。
5.当前程序在运行的过程中会加载一些共享库,也就是动态链接库:windows下就是.dll,Linux下就是so
6.在我们程序运行中函数运行或产生线程时每一个独有的stack。且栈是从高地址向低地址进行增长。
内核空间:
主要分为
ZONE_DMA 大概16M的大小。
ZONE_NORMAL 大概有800多M,进程空间的PCB块进程控制块都在里面存放,以及内核空间的线程还有内核函数在运行时所依赖的栈空间。
ZONE_HIGHMEM 这是映射我们高地址的物理内存的时候做地址映射用的。
每一个进程的用户空间是私有的但是内核空间是共享的