page fault

当我们向操作系统申请内存时,操作系统并不是直接分配给我们物理内存,而是只标记当前进程拥有该段内存,当真正使用这段段内存时才会分配。

这种延迟分配物理内存的方式就通过page fault机制来实现的。

当我们访问一个内存地址时,

1.如果该地址非法(访问系统为进程分配的地址空间之外的物理内存),或者我们对其没有访问权限;

2.

如果地址合法,权限也正确,那么还得分两种情况来讨论。第一种情况是PTE不存在,这会出现在:

  • 对于anonymous page,用户空间使用malloc()进行内存申请时(对应底层的实现是mmap或者brk),内核并不会立刻为其分配物理内存,而只是为请求的进程的rbtree管理的vma信息中记录(添加或更改)诸如内存范围和标志之类的信息。

只有当内存被真正使用,触发page fault,才会真正分配物理页面和对应的页表项,即demand alloction,对应的函数实现是do_anonymous_page()。通过mmap映射建立的heap和stack等内存区域,在初始未使用时,也适用于这样的规则。

  • 对于page cache, 在发生内存回收后,部分text(code)段的页面会被discard,部分data段的页面会被writeback,之后再次访问这些页面,也将出现page fault。此时,需要从外部存储介质中,将页面内容调回内存,即demand paging,对应的函数实现是do_fault()。

图片来源于http://jake.dothome.co.kr/wp-content/uploads/2017/01/do_fault-1.png

第二种情况是PTE存在,但其中的"P(resent)"位为0,说明这是一个之前被swap out出去的anonymous page。现在PTE里存储的不是物理页面的编号PPN,而是外部swap area中slot的编号swp_entry_t,需要通过do_swap_page(),执行swap in操作将页面的内容拷贝回内存。

/* orig_pte是指发生page fault时的PTE */
if (!pte_present(vmf->orig_pte))
    return do_swap_page(vmf);

发生page fault时,如果目标页面驻留在外部存储器,那么需要开销较大的I/O操作,这种page fault被称为"major"的。而如果目标页面就在内存中(比如swap cache),只是缺少一个对该页面的引用而已,这种page fault不需要重新分配内存页面,代价较小,因此被称为"minor"的。

 

Linux进程如何访问内存

        Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源,原因后面会讲到。

为什么需要虚拟内存地址空间

       假设某个进程需要4MB的空间,内存假设是1MB的,如果进程直接使用物理地址,这个进程会因为内存不足跑不起来。既然进程不是直接访问物理内存,那么进程中涉及的内存地址当然也不是物理内存地址。而是虚拟的内存地址,虚拟的内存地址和物理的内存地址之间保持一种映射关系,这种关系由MMU进行管理。每个进程都有自己独立的虚拟地址空间。

 

参考:https://zhuanlan.zhihu.com/p/66046257

https://cloud.tencent.com/developer/article/1459526

posted @ 2020-12-15 16:32  zeroPatrick  阅读(619)  评论(0编辑  收藏  举报