- 论坛徽章:
- 0
|
通过对FreeBSD设计与实现一书的阅读,并结合源码分析,将自己对FreeBSD系统的内存管理部分的一些理解摆在这里,希望高手,大拿们指点啦。
系统内存管理
一、基本概念
Address Translation:虚拟地址空间到物理存储空间的映射
内存管理单元(MMU) :实现地址转换操作与进程地址隔离保护的硬件。
Paging:分页操作就是将进程访问到的页面读入主存(当发生page fault时),而把不再活跃的页面写入后备存储来节约进程的主存消耗的技术。
Swapping:系统内存不足时,选择暂时换出到次存的进程的内存管理策略。
虚拟地址空间,以及地址翻译机制使得进程地址可以独立于具体的存储器位置。
要避免一个进程访问别的进程的内容,要有硬件保护。Memory Management Unit(MMU)结合了进程地址空间保护和地址翻译功能。
![]()
图一.地址翻译示意图
地址翻译将虚拟地址空间与物理地址空见解耦。每个虚拟页面可能保存在主存中,也可能不在主存中。当进程访问不在主存中的虚拟地址,硬件将产生缺页错误(page fault)。处理缺页错误或称分页(paging),按需加载页,使得进程可以在只有部分页面驻留主存的情况下执行。
缺页处理需要确定以下三种策略:
fetch policy,读取策略,FreeBSD为了减少I/O操作次数,希望一次读入尽量多的页面,采用prepaging策略,一般是需要页面前后各8个页面内可以一次读入的部分。
placement policy,放置策略,FreeBSD为了充分利用Cache功能,采用Color算法来确定读入页面放置的物理位置。
replacement policy,替换策略,FreeBSD维持多个链表管理和释放物理空间,以便重用。
进程对内存的操作具有局部集中性(locality of reference)。当进程在某个子流程或者循环中时,很可能固定的引用一段内存空间,称作working set,工作集。进程可能周期性的改变工作集。
swap在内存短缺时执行整个进程的换入换出。不过现在与分页相结合,直到大的短缺时,才swap.
硬件支持:
要避免一个进程修改别的进程,就要禁止进程修改它自己的内存地址映射。
当进程换出时硬件要支持指令执行状态信息的保存。
脏页标志。
二、内存管理总览
FreeBSD系统的内存管理基于部分面向对象思想:将文件,匿名内存段等所有数据源归结为object,定义对这些数据源的标准操作接口(pager, pagerops),并根据不同的数据源采用不同的操作实现(如swappagerops,vnodepagerops)。物理内存只是用来作为这些对象最近所使用的页面的缓存。
虚拟内存到物理内存部分的实际映射交给pmap模块完成
FreeBSD内存管理相关数据结构:
vmspace 表示内核或一个进程的地址空间,包含硬件独立的内容,也包含硬件相关的内容。
Vm_map 包含硬件无关的虚拟地址空间的描述。
Vm_map_entry 使用相同存储介质,并且保护和继承方式也相同的虚拟连续的地址段
Vm_page 代表虚拟内存系统中内存页管理的数据结构。
数据结构名称
说明
vmspace
用于描述一个进程的地址空间,包括机器相关的与机器无关的结构
vm_map
用于描述机器无关的虚拟地址空间的高级抽象数据
pmap
机器相关虚拟地址与物理地址映射结构
vm_map_entry
用于描述一个虚拟的连续地址空间,它们拥有共同的保护属性与继承属性,并且使用相同的备份存储对象
vm_object
表示一个地址范围的数据源
shadow_object
表示已经修改过的数据,是一种object的特殊形态
vm_page
这是最底层的数据结构,表示虚拟内存所使用的物理内存
这些数据结构中的重要字段
struct vmspace {
struct vm_map vm_map; /* 硬件无关虚拟内存管理 */
struct pmap vm_pmap; /* 硬件相关映射 */
/* 地址空间各段数据 */
/* 一些统计信息 */
......
};
struct vm_map {
struct vm_map_entry header; /* vm_map_entry链表 */
vm_map_entry_t root; /* vm_map_entry二叉树结构 */
/* 同步机制,大小信息,状态标志 */
......
};
struct vm_map_entry {
/* vm_map_entry链表及二叉树结构 */
struct vm_map_entry *prev; /* previous entry */
struct vm_map_entry *next; /* next entry */
struct vm_map_entry *left; /* left child in binary search tree */
struct vm_map_entry *right; /* right child in binary search tree */
/* 始末地址和大小数据 */
vm_offset_t start; /* start address */
vm_offset_t end; /* end address */
vm_offset_t avail_ssize; /* amt can grow if this is a stack */
/* 这两个值都是vm_map_entry 在插入binary search tree (vm_map_entry_link)时算出来的,用来寻找合适的free空间 */
vm_size_t adj_free; /* amount of adjacent free space,邻接的free空间 */
vm_size_t max_free; /* max free space in subtree 其子树的最大free空间*/
/* 指向object结构,在内核映射中可能指向子映射 */
union vm_map_object object; /* object I point to */
vm_ooffset_t offset; /* 在object中的偏移量*/
vm_eflags_t eflags; /* map_entry的类型标志,其中MAP_ENTRY_IS_SUB_MAP表示其为submap*/
/* Only in task maps: */
vm_prot_t protection; /* protection code */
vm_prot_t max_protection; /* maximum protection */
vm_inherit_t inheritance; /* inheritance */
int wired_count; /* 不可换页标志 can be paged if = 0 */
vm_pindex_t lastr; /* last read */
};
vm_map_object联合,包括指向vm_object的指针,内核映射中可能指向子映射vm_map结构
union vm_map_object {
struct vm_object *vm_object; /* object object */
struct vm_map *sub_map; /* belongs to another map */
};
struct vm_object {
struct mtx mtx;
/* shadow object 相关数据 */
TAILQ_ENTRY(vm_object) object_list; /* list of all objects */
LIST_HEAD(, vm_object) shadow_head; /* objects that this is a shadow for */
LIST_ENTRY(vm_object) shadow_list; /* chain of shadow objects */
TAILQ_HEAD(, vm_page) memq; /* 驻留主存页链表 list of resident pages */
vm_page_t root; /* 内存页二叉树根root of the resident page splay tree */
vm_pindex_t size; /* Object size */
int generation; /* generation ID */
int ref_count; /* How many refs?? */
int shadow_count; /* how many objects that this is a shadow for */
objtype_t type; /* pager 类型*/
u_short flags; /* see below */
u_short pg_color; /* color算法中该对象采用的起始颜色*/
u_short paging_in_progress; /* Paging (in or out) so don't collapse or destroy */
int resident_page_count; /* number of resident pages */
struct vm_object *backing_object; /* object that I'm a shadow of */
vm_ooffset_t backing_object_offset; /* Offset in backing object */
TAILQ_ENTRY(vm_object) pager_object_list; /* list of all objects of this pager type */
/* 与vm_object对应的结构,在vnode pager中指向vnode结构,在swap pager中指向swap空间 */
void *handle;
/* pager相关数据 */
......
};
struct vm_page {
/* 内存页的多列表,二叉树结构 */
TAILQ_ENTRY(vm_page) pageq; /* queue info for FIFO queue or free list (P) */
TAILQ_ENTRY(vm_page) listq; /* pages in same object (O) */
struct vm_page *left; /* splay tree link (O) */
struct vm_page *right; /* splay tree link (O) */
/* 页面的object及位置信息 */
vm_object_t object; /* which object am I in (O,P)*/
vm_pindex_t pindex; /* offset into object (O,P) */
vm_paddr_t phys_addr; /* physical address of page */
/* 机器相关数据结构,完成反向映射 */
struct md_page md; /* machine dependant stuff */
u_short queue; /* page queue index */
u_short flags, /* see below */
pc; /* page color */
<span style="m
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/9478/showart_43684.html |
|