进程
一个进程在内存中是什么样的?
一个进程就是一段运行的代码,那运行的代码会有哪些东西呢?
- 正文段,也就是代码,一个程序要运行肯定需要代码的
- 数据段,我们在写代码时总是会定义各种数据结构,而数据结构自然要占据内存,因此我们将其表示为数据段,数据段一般是可增长的,因为我们经常会在代码中动态分配内存如
malloc
函数 - 堆栈段,堆栈段不同于数据段和代码段,它一般保存着一些与程序控制有关的东西,如一个
linux
命令,cp src dst
,这一行命令表示拷贝src
文件到dst
文件,那进程的堆栈段会保存这三个参数,另外,进程的堆栈段还会保存struct thread_info
(根据该结构可以找到进程的进程描述符),该结构放在进程堆栈段的顶端和底端(与堆栈段增长方向相反),这样内核就能很快找到每一个进程的struct task_struct
,加快内核的运行速度
现在我们知道了一个运行的代码是如何使用内存的了
虚拟内存
为什么需要虚拟内存?
可以看一下内存使用这篇文章,简单来说就是我们希望将整个物理内存分成每一页称为页框,然后程序运行时需要的内存称为页面,**这样有什么用呢?**有了分页的概念,那么我们其实可以在程序运行时动态的调入和调出页面,因为一个程序的运行其实并不需要所有的所有的页面都在内存中,它不需要的页面我们就可以调出,需要页面时就调入,还有一个好处就是虚拟内存让每一个程序以为自己独占整个内存(只要将虚拟地址映射到物理地址即可),甚至虚拟内存还能大于物理内存
一个进程是如何使用虚拟内存的?
页表: 通过页表,程序就能将一段虚拟地址转换成物理地址,举一个简单的例子,假设一个32
位计算机,那么它的寻址能力就是0~2^32
也就是0~4G
,现在假设计算机内存分页大小为4KB
,也就是2^12
,那我们知道页框号范围就是2^(32-12)
即2^20
,如果我们使用二级页表,那么我先通过32
地址的前十位在页表中找到页表号,接下来根据找到的页表号所指的另一个页表,找到该页表后我们再根据32
位地址的中间10~20
位找到页表项,通过该页表项我们就能得到页框号了,最后根据页内偏移(32位地址的最后12位)
找到该虚拟地址的物理地址,这就是进程使用虚拟地址的过程
具体还可以看这篇博客通过一个变量的虚拟地址找到物理地址并通过修改物理地址对应的值来改变变量的值
内存管理
基于linux2.6
内核
linux
维护一个mem_map
数组(页描述符数组),每一个页描