Linux内存管理的基本框架⭐⭐

Linux内核的映射机制设计成三层,在页面目录和页面表中间增设了一层“中间目录”。
在代码中,页面目录称为PGD中间目录称为PMD,而页面表称为PT
PT中的表项称为PTE,PTE是“Page Table Entry”的缩写。
PGD、PMD和PT均为数组。
在逻辑上也把线性地址从高位到低位划分成4个位段。

4G字节虚存空间
Linux内核将这4G字节的空间分成两部分:
将最高的1G字节(从虚地址0xC0000000至0xFFFFFFFF)用于内核本身,称为“系统空间”。
将较低的3G字节(从虚地址0x0至0xBFFFFFFFF)用作各个进程的“用户空间”
系统空间由所有进程共享。
每当一个进程通过系统调用进入了内核,该进程就在共享的系统空间中运行,不再有其自己的独立空间。


虽然系统空间占据了每个虚存空间中最高的1G字节,在物理的内存中却总是从最低的地址(0)开始。
对于内核来说,其地址的映射是很简单的线性映射,0xC0000000就是两者之间的位移量。
此位移称为PAGE_OFFSET,定义于文件include/asm-i386/page.h中。
PAGE_OFFSET也代表着用户空间的上限,常数TASK_SIZE就是通过它定义的。
对于系统空间而言,给定一个虚地址x,其物理地址是从x中减去PAGE_OFFSET;相对应地,给定一个物理地址x,其虚地址是x+PAGE_OFFSET

_pa()只是为内核代码中当需要知道与一个虚地址对应的物理地址时提供方便。
例如,在切换进程的时候要将寄存器CR3设置成指向新进程的页面目录PGD,而该目录的起始地址在内核代码中是虚地址,但CR3所需要的是物理地址,这时候就要用到_pa()。


每个进程的局部段描述表LDT都作为一个独立的段而存在,在全局段描述表GDT中要有一个表项指向这个段的起始地址,并说明该段的长度以及其他一些参数。
每个进程还有一个TSS结构(任务状态段)
每个进程都要在全局段描述表GDT中占据两个表项


段寄存器中用作GDT表下标的位段宽度是13位,所以GDT中可以有8192个描述项。
一些系统开销:(GDT中的第2项和第3项分别用于内核的代码段和数据段,第4项和第5项永远用于当前进程的代码段和数据段,第1项永远是0,等等)
有8180个表项可供使用,所以系统中最大的进程数量是4090。

①物理内存管理:

Linux内存最小管理单位为页(page),通常一页为4K。初始化时,linux会为每个物理内存也建立一个page的管理结构(切记是linux系统不是uboot,也就是物理内存的管理肯定是在linux系统上的),操作物理内存时实际上就是操作page页。某些设备会映射在物理内存地址外,这些地址会在使用时建立page结构。

②进程内存管理:

Linux进程通过vma进行管理,每个进程都有一个task_struct结构体进行维护,其中的mm_struct结构体管理这进程的所有内存。Mm_struct中维护者一个vma链表,其中的每一个vma节点对应着一段连续的进程内存。这里的连续是指在进程空间中连续,物理空间中不一定连续。如果使用malloc等申请一段内存,则内核会给进程增加vma节点。

--

原文地址:https://www.cnblogs.com/Ph-one/p/8537291.html