linux内核内存管理子系统概要分析

内存管理

目标

内存管理子系统提供下面的能力给客户:

大的地址空间-用户能够引用更多的内存,而不是局限于物理内存。 保护- 一个进程的地址空间私有,不能被其他进程读取; 还有,内存管理子系统阻止进程覆盖自己的代码和只读数据。 内存映射-客户可以映射文件到自己的虚拟内存区域,读文件操作可以通过读这部分被映射的内存来实现。 公平的存取物理内存- 内存管理子系统确保所有的进程公平的取得物理内存,这样也就保证了系统的执行性能。 共享内存- 内存管理子系统允许进程共享他自己的一块内存给其他进程. 例如, 可执行代码通常在相关进程中共享.

对外接口

内存管理子系统提供两个功能界面: 一个是给用户进程使用的系统调用界面, 另外一个是给其他内核子系统使用来完成他们的任务的调用界面。

系统调用界面

malloc() / free() – allocate or free a region of memory for the process’s use

mmap() / munmap() / msync() / mremap() – map files into virtual memory regions

mprotect – change the protection on a region of virtual memory

mlock() / mlockall() / munlock() / munlockall() – super-user routines to prevent memory being swapped

swapon() / swapoff() – super-user routines to add and remove swap files for the system

内核内部调用界面

kmalloc() / kfree() – allocate and free memory for use by the kernel’s data structures

verify_area() – verify that a region of user memory is mapped with required permissions

get_free_page() / free_page() – allocate and free physical memory pages

另外, 内存管理子系统使他的所有数据结构和大部分子例程在内核内部可见。许多具备内存管理的内核子系统模块通过存取这些数据结构来实现系统的细节.

系统描述

由于linux支持多种硬件平台,内存管理子系统通过一个内存平台规格来抽象所有硬件平台的硬件细节,从而有能力对外提供统一的内存管理接口. 所有存取到硬件内存的进程都通过这个抽象接口来完成。

内存管理子系统使用硬件内存管理系统来映射虚拟地址到物理地址(进程使用的)。当一个用户进程存取一个内存位置的时候,硬件内存管理系统就转换这个虚拟地址到物理地址,然后,使用这个得到的物理地址执行存取操作。因为这样的映射使用户进程不必关心于虚拟地址联系的物理地址是什么。这就允许内存管理子系统移动进程所在物理内存。另外,如果两个用户进程的虚拟地址映射到了同样的物理地址,则这种映射允许这两个用户进程共享同样的物理内存。

另外,在进程内存不再使用的时候,内存管理子系统交换进程内存到分页文件中。这就允许系统使用比实际物理内存多的空间来执行进程。内存管理子系统包含一个守护进程(kswapd). Linux用术语daemon来指代一个内核线程。一个daemon被进程调度器调度,调度放放和用户进程的调度方法是一样的。但是,一个daemon可以直接存取内核数据结构。这样,daemon 的概念就比用户进程更加像一个线程了。

这个kswapd daemon 定期检查看看是否有任何物理内存页在近期没有被引用,这些页将被从物理内存中逐出。如果必要,他们就会被存储到磁盘上。内存管理子系统特别关心减少磁盘被请求的活动量。如果这些页面能够能够使用另外的方式被重新获得,内存管理子系统避免写这些页面到磁盘。

硬件内存管理系统检测到用户进程存取的内存地址不在当前可用的虚拟到物理内存的映射范围内时,它通知linux内核有页失效发生,并呼唤内存管理子系统来解决这个问题。页失效有两种可能性:一个是这个也现在已经被交换到了硬盘上-必须被换回内存中,另外一种是用户进程制造了一个无效的内存地址引用-可能是超出了进程被映射的内存空间。硬件内存管理系统也检测对内存地址的无效引用-就像写道执行代码空间或者只读数据空间--这种引用也产生页失效报告给内存管理子系统,如果内存管理子系统检测到了一个无效的内存引用,他就用一个信号通知这个进程。如果这个进程不处理这个信号,他就会被强行终止。

数据结构

1。对于地址宽度为32位的CPU,用两层页式管理就够了,但对于地址宽度大于32位的CPU刚需要用到三层页式管理才能实现线性地址到物理地址的映射。页面目录-PGD,中间目录-PMD,页面表-PT,PT中的表项-PTE。

2。线性地址到物理地址的映射原理

从CPU发出的线性地址,虚拟的内存管理单元分4步从线性地址转换到物理地址

1)用线性地址中的最高那个位段作为下标在PGD中找到相应的表项,此表项指向相应的中间目录PMD。

2)用线性地址中的第二个位段作为下标在PMD中找到相应的表项,此表项指向相应的页面表。

3)用线性地址中的第三个位段作为下标在页面表中找到相应的表项PTE,此表项中存放的就是指向物理页面的指针。

4)线性地址中的最后位段作来物理页面的内的相对偏移量,将此位移量与目标物理页面的起始地址相加便得到相应的物理地址。

3。虚拟地址空间的分布

32位地址意味着4GB的虚拟空间,LINUX内核将其分成两部分,将最高的1G(0XC0000000-0XFFFFFFFF)作为内核本身,称为“系统空间”。而将最低的3G(0X0-0XBFFFFFFF)作为各个进程的“用户空间”。理论上每个进程的用户空间都为3G。

4。页式管理与段式管理

LINUX内核采用页式存储管理,虚拟地址空间划分成固定大小的页,由MMU在运行时将虚拟地址映射成某个物理内存页面中的地址。相对段式管理有很多好处。1)页面是固定的,便于管理。2)换出时效率高。

5。CPU执行程序时用的是虚拟地址,而MMU硬件在进行映射时用到的是物理地址,这由switch_mm()函数完成。/include/asm-i386/mmu_context.h。在页面映射过程中,CPU要访问内存三次,第一次是页面目录,第二次是页面表,第三次才是真正的目标。所以虚存的高效实现只要依赖于高速缓存的实现。第一次用到的页面目录和页面表要到内存中读取,一但装入到高速缓存就不再需要在内存中去找,并且这整个过程是由硬件实现,所以速度很快。

6。重要的数据结构

页面目录PGD,中间目录PMD,页面表PT分别是由表项pgd_t,pmd_t pte_t构成的,这些表项是数据结构。在include/asm-i386/page.h中实现。

一个人,一条路,人在途中,心随景动,

linux内核内存管理子系统概要分析

相关文章:

你感兴趣的文章:

标签云: