调用malloc时发生了什么(3) - 缺页中断
页表的创建
kmalloc内存使用了umapped内存,直接对地址偏移即可寻址物理内存,这里不考虑。
考虑用户态内存和vmalloc,都用到了虚拟内存,即需要通过页表查询的方式查询都物理内存。
例如 用户态通过brk申请了一块内存,后续访问这块内存的0x00007F88F16A4690
这块地址会发生什么?
首先,X64内核是4级页表,根据X64对线性地址的划分,可以计算出0x00007F88F16A4690
这地址的pgd索引是 255, pud索引是 35, pmd索引是 395, pte索引是 164。
因为x64体系结构,pgd索引为 47~39 bit,pud索引为 38~30 bit,pmd索引为 29~21 bit,pte索引为 20~12 bit。
如果这块内存的地址没有存在MMU/TLB,则会触发缺页中断,常见的缺页中断就是该地址第一次访问,先来看下缺页中弄断时,页表是如何创建的:
首先,从current->mm->pgd
取出全局页表的首地址,current->mm->pgd
是pgd_t
类型数据结构,其实就是8字节的unsigned long
地址,所以根据 pgd索引可以获得pgd = current->mm->pgd + 255,
接着,取出的pgd中,即获取*pgd中的值,也是一个unsigned long的值。
*pgd为NULL的话,创建一个page1,page1的页框号,就保存在 pgd中,而pud的值,就是该page的对应的虚拟地址加上358字节,换句话说,*pgd具体存着pud的页框号,通过该页框号,能够找到page,然后通过
内存偏移能够找到当前地址对应的pud。
同理,*pud 为null的话,也会创建一个page2,pud 保存page2的页框号,pmd就是page2的虚拟地址加上 3958。
最后,*pmd为null的话,创建一个page3,pmd存入page3的页框号,pte的地址就是page3的虚拟地址加上 1648。
用图来描述,就是下面这样子:
mm->pgd
----
| 0 |
----
.
.
. *pgd
---- pgd ----
| 255| -> | 0 |
---- ----
. .
. . *pud
. ---- pud ----
---- | 35 | -> | 0 |
| 511| ---- ----
---- . .
. . *pmd
---- ---- pmd ----
| 511| | 395| -> | 0 |
---- ---- ----
. .
. .
---- ---- pte(8字节)
| 511| | 164| <-
---- ----
.
.
----
| 511|
----
至此寻址到了内存地址对应的pte,但是虚拟地址对应的物理地址还未创建,上面描述的page1,page2,page3都是为了构建多级页表创建内存而已。
物理内存的创建是在函数do_anonymous_page
中完成。do_anonymous_page
函数中,对于读操作,分配一个zero page
,它是一个固定的页,启动就分配好的页,因为走到 do_anonymous_page
这步时,必然是因为虚拟内存对应的屋里内存还未创建,所以此时用户态的read
类型的操作,返回0即可,其实返回任意数据即可。且将这个pte标记没有设置成可写。这样意味着
后续的写操作,会申请新的page,这个page才是虚拟地址对应的物理内存。(在do_wp_page
中处理)。
回到上面的图,我们来看一下,一个进程最坏情况下,一个进程页表最大会多大?看上图,一个pmd 4k,一个pud有512个pmd,一个pgd有512个pmd,总共512个pgd,
所以总共会消耗内存:4k512512*512 = 549755813888 bytes = 512G。还有一种更简单的算法,就是64bit有效地址范围是48字节,所以总共内存2^48,而又被4k大小的page分割,所以
会被划分成 248/212 个 page,而一个page需要8字节的pte来表示所以(248/212)*2^3 = 2^39 = 549755813888 = 512G。
pte
这个pte就是被会缓存在TLB中,可见上面极端情况下,一个进程会有 549755813888/8 个pte表,如果进程申请的内存够大,访问够随机,基本次次tlb miss。
pagesie
上面描述的pagesize是4k,如果pagesize大一点会怎么样。我们举个极端例子,内存是512GB,pagesize是256GB,显然,一个进程只需要2 pte就能构建虚拟地址和物理地址映射关系。
而pte的数量急剧减少,被TLB淘汰的概率几乎没有。但是劣势也非常明显,如果进程开辟1字节的内存,就需要申请一个256G的page。
上一篇: create new post for jekyll
下一篇: Java连接各种数据库的实例