`
Joard
  • 浏览: 28998 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

FreeBSD学习随记之三 储存管理

    博客分类:
  • OS
阅读更多

三,储存管理

 

1. 虚拟地址空间布局

在一个 32 位机器上,可以分配 1-2GB 的虚拟内存空间供内核使用。

 

2. 虚拟内存的数据结构

vmspace

Structure that encompasses both the machine-dependent and machine-independent structures describing a process's address space

vm_map

Highest-level data structure that describes the machine-independent virtual address space

vm_map_entry

Structure that describes a virtually contiguous range of addresses that share protection and inheritance attributes and that use the same backing-store object

object

Structure that describes a source of data for a range of addresses

shadow object

Special object that represents modified copy of original data

vm_page

The lowest-level data structure that represents the physical memory being used by the virtual-memory system

 

Data structures that describe a process address space.

 

3. 内核映射与子映射

    与任何进程一样,内核有一个 vm_map 结构以及相应的一组 vm_map_entry 结构来描述一段地址范围的使用情况。

    子映射是内核独有的结构,它用来隔离和限制给内核子系统分配的地址空间。在需要连续的若干内核地址空间的子系统中会用到它。

Kernel address-space maps.

 

4. 内核地址空间的分配

    1> 不可调页的地址范围

    也叫做固定的地址范围,在调用时就给它分配物理内存, pageout 守护进程不会替换这段内存。固定的页面从来不产生可能引发一次阻塞操作的缺页,固定的内存有 kmem_alloc() kmem_malloc() 分配。

 

    2> 可调页的地址范围

    可调页的内核虚拟内存可以用 kmem_alloc_pageable() kmem_alloc_wait() 来分配。可调页的地址范围是在需要时才分配物理内存的,而且作为正常替换策略的一部分,该内存可以由 pageout 守护进程回写到后备存储器上。

 

5. 内核的存储分配

    1> 分配策略

    利用率 = 需要量 / 请求量

    需要量是已经获得但尚未释放的内存总量;请求量是已经为内存池分配的内存量,用内存池中的内存来满足需要量。由于碎片的存在以及要保留一些空闲内存为以后的需求做好准备,所以存储分配程序请求的内存量要比需要量更多。

    内存对分配少量内存和分配大量内存采用了混合策略。分配少量内存使用 2- 幂表策略 (power-of-2 list strategy) 。如区域存储分配程序中,这些区域的大小按 2 的幂依次从 16 个字节增加到一个页面的大小。也即 2- 幂算法分配大小为 1,2,4,8,…,n 。分配大块内存时采用按页面的倍数分配内存,也即 1,2,3,4,….,n 。首先把需要分配的大内存向上取整为页面大小的倍数。接下来,分配程序使用“首次匹配”算法在为动态分配保留的内核地址空间中找到可以分配的空间。

 

    2> 区域存储分配程序

    比如进程,线程, vnode 和控制块结构,这些结构有几个共同的特征:

  1. 它们倾向于变大,因而容易浪费空间。

  2. 它们往往很常用。

  3. 它们经常会链接到一起构成长链表。

  4. 这些结构常常会包含许多必须在使用之前初始化过的链表和锁。

出于上述原因, FreeBSD 提供了一个区域分配程序 (zone allocator) ,有时候也称为分片分配程序 (slab allocator) 。区域分配程序提供了一个高效接口,用于管理一群大小和类型相同的结构。

    区域是有大小相等的结构所构成的一个可以扩展的集合。新的区域用函数 uma_zcreate() 来创建。它必须指定要分配的结构的大小,并且要登记两组函数。第一组函数在从区域内分配或者释放一个结构时调用。第二组函数在给区域分配或者释放内存时调用。新的结构用 uma_zalloc() 函数来分配,它接受一个由 uma_zcreate() 返回的区域标识符作为参数, uma_zfree() 函数用来释放结构,它接受一个区域标识符和一个指向要被释放的结构的指针作为参数。区域存储分配程序不在分配的每块内存中保存它自己的大小信息,而是把大小信息和内存页关联起来。在分配的内存块之外保存所分配内存的大小。

 

6. 进程的虚拟地址空间的构成

    这里的 object 通常用来保存有关一个文件或者一块匿名内存区域的信息。不管其是被系统中的单个进程还是多个进程所映射,总是用同一个 object 来表示它。

 

Object 保存如下信息:

  1. 该对象当前驻留在主存中的页面链表;其中每一个页面可能被同时映射到多个地址空间中,但是它始终只为一个 object 所有;

  2. 该对象被 vm_map_entry 结构或其他对象引用的次数;

  3. 该对象所描述的文件和匿名区域的大小;

  4. 该对象驻留内存的页面数;

  5. 指向影子对象的指针;

  6. 该对象所用调页器的类型;

 

系统中总共有 3 种类型的对象:

  1. 命名 (named) 对象表示文件;它们也可以用来表示那些能够提供可映射内存的硬件设备;

  2. 匿名 (anonymous) 对象用来表示那些在初次使用时被清零的内存区域;在不再需要的时候,他们会被直接丢弃;

  3. 影子 (shadow) 对象用来存放在页面被修改后的私有副本;当它们不再被引用时,就被自动丢弃。

 

7. 创建进程

    FreeBSD 采用写时复制技术来创建进程, fork 操作所涉及到的父进程和子进程都引用相同的物理页面,而不是复制父进程的每一个内存页面,任何修改操作都产生保护错误,从而为其创建私有快照。

    vfork 与普通的 fork 不同,其实现总是比“写时复制”方式的实现效率高,因为内核不用为子系统复制地址空间,而是简单地把父进程的地址空间传递给子进程,并挂起父进程。当然, vfork 这种调用在结构上是有缺陷地—子进程得到控制权后可以修改父进程的内容和地址空间的大小。 vfork 应该是在写时复制之前出现的。

 

8. 文件映射

    系统调用 mmap 可以把一个文件映射到一块地址空间。

Five types of overlap that the kernel must consider when adding a new address mapping.

 

9. 调页器 (paper)

    调页器接口提供了在后备存储 (backing store) 和物理内存 (physical memory) 之间转移数据的机制。其负责提供数据来填充页面,以及在页面被修改后提供一个位置保存该页。

调页器定义的操作如下:

Operation

Description

Pgo_init()

initialize pager

pgo_alloc()

allocate pager

pgo_dealloc()

deallocate pager

pgo_getpages()

read page(s) from backing store

pgo_putpages()

write page(s) to backing store

pgo_haspage()

check whether backing store has a page

pgo_pageunswapped()

remove a page from backing store (swap pager only)

目前系统支持 4 种类型的调页器:

1> vnode pager

    vnode 调页器处理的对象映射了以讹文件系统中的文件。不管文件是通过 open 显式地打开,还是通过 exec 隐式地打开,系统都要给它分配一个 vnode 。在分配一个新的 vnode 的过程中,一是要分配一个对象来保存该文件的页面,二是要将该对象关联到 vnode 调页器。然后设置调页器句柄指向 vnode ,同时私有数据保存了文件的大小。如果对一个文件做了私有映射,那么修改过的页面就不能被写回文件系统。这种映射必须使用一个影子对象和交换调页器来处理所有修改过的页面。所以说,不会要求一个私有映射对象将脏数据写回它所属的文件。

 

    2> device pager

    设备调页器处理的对象代表映射到内存的硬件设备。映射到内存的设备提供的接口看起来就像是一段内存空间。设备调页器与其他三种调页器有根本区别,因为它并不在给定的物理内存页面中填入数据。相反,它创建并管理一个自己的 vm_page 结构,每一个结构表示设备空间的一个页面。这些页面的链表头保存在对象的调页器私有数据区内。这种方法使设备的存储器看上去就像系统直接安装的物理存储器。因此在虚拟内存中不需要特别的代码来处理设备的存储器。

 

    3> physical-memory pager

    物理内存调页器处理的对象包含有非嗲也内存。它们只用于 System V 的共享接口,该接口可以通过配置来使用非调页内存,代替默认使用的可交换内存。

 

    4> swap pager

    交换调页器一词是指两种功能不同的调页器。最常用的交换调页器是指由映射匿名内存的对象所使用的调页器。这种调页器有时候也称为 default pager ,它提供了通常所说的交换空间:在第一次访问时清零的临时性后备存储空间。当第一次创建一个匿名对象的时候,给它指派的就是默认调页器。默认调页器既不分配资源也不提供后备存储。但是,当 pageout 守 护进程第一次要求将一个处于活动状态的页面从某个匿名对象里移除的时候,默认调页器就会用交换调页器代替它自己。交换调页器负责管理交换空间:它计算出把 脏页保存在哪里,当再次需要它们的时候如何找到它们。影子对象要求这些操作必须高效执行,一个典型的影子对象分布会很分散。其次,对交换调页器要求能够以 异步方式写回脏页面,这对于单线程的 pageout 守护进程很有必要。

 

 

10. 调页机制

三个重要策略来定义调页系统:

  1. 何时系统把页面载入内存—取页策略 (fetch policy)

  2. 系统把页面放在何处—放置策略 (placement policy)

  3. 当放置操作向主存申请不到放置页面的空间时,如何选择要从主存里删除的其他页面—替换策略 (replacement policy)

 

缺页处理:

/*

* Handle a page fault occurring at the given address,

* requiring the given permissions, in the map specified.

* If successful, insert the page into the associated

* physical map.

*/

int vm_fault(

vm_map_t map,

vm_offset_t addr,

vm_prot_t type)

{

RetryFault:

lookup address in map returning object/offset/prot;

first_object = object;

[A] for (;;) {

page = lookup page at object/offset;

[B] if (page found) {

if (page busy)

block and goto RetryFault;

remove from paging queues;

mark page as busy;

break;

}

[C] if (object has nondefault pager or

object == first_object) {

page = allocate a page for object/offset;

if (no pages available)

block and goto RetryFault;

}

[D] if (object has nondefault pager) {

scan for pages to cluster;

call pager to fill page(s);

if (IO error)

return an error;

if (pager has page)

break;

if (object != first_object)

free page;

}

/* no pager, or pager does not have page */

[E] if (object == first_object)

first_page = page;

next_object = next object;

[F] if (no next object) {

if (object != first_object) {

object = first_object;

page = first_page;

}

first_page = NULL;

zero fill page;

break;

}

object = next_object;

}

[G] /* appropriate page has been found or allocated */

orig_page = page;

[H] if (object != first object) {

if (fault type ==WRITE) {

copy page to first_page;

deactivate page;

page =first_page;

object =first_object;

} else {

prot &=~ WRITE;

mark page copy-on-write;

}

}

[I] if (prot &WRITE)

mark page not copy-on-write;

enter mapping for page;

enter read-only mapping for clustered pages;

[J] activate and unbusy page;

if (first_page != NULL)

unbusy and free first_page;

}

 

 

硬件高速缓存的算法,实际的高速缓存全部由硬件实现:

struct cache {

vm_offset_t key; /* address of data */

char data[LINESIZE]; /* cache data */

} cache[CACHELINES][SETSIZE];

 

/*

* If present, get data for addr from cache. Otherwise fetch

* data from main memory, place in cache, and return it.

*/

hardware_cache_fetch(vm_offset_t addr)

{

vm_offset_t key, line;

 

line = (addr / LINESIZE) % CACHELINES;

for (key = 0; key < SETSIZE; key++)

if (cache[line][key] .key == addr)

break;

if (key < SETSIZE)

return (cache[line][key].data);

key = select_replacement_key(line);

cache[line][key].key = addr;

return (cache[line][key].data = fetch_from_RAM(addr));

}

 

 

12.page coloring

    页面填色是一种性能优化措施,设计它是为了确保对虚拟内存中的连续地址的访问可以充分地利用物理地址的高速缓存。页面填色算法的作用是确保虚拟内存中连 续的页面在高速缓存看起来也是连续的。页面填色算法不是给虚拟地址随机地分配物理页面,而是把在高速缓存看起来是连续的物理页面分配给虚拟地址。两个物理 页面如何它们命中了高速缓存内的连续页面,则称它们是高速缓存连续的 (cache-contiguous)

    为了确保均匀地使用颜色,下一个对象使用的起始颜色值要更换,变化幅度这样选择:即这个对象的大小和 L1 高 速缓存大小的三分之一相比,两者中较小的那一个。在一个对象上发生缺页时,新页面的首选颜色这样计算:对象所缺页的逻辑页号加上该对象的起始颜色,再对颜 色数取模。如果所得颜色的空闲链表里有页面可用,就从那个颜色的空闲链表里取得这一新页。否则,检查和所要求的颜色相距最远的颜色,直至找到一个可用的页 面。

从高速缓存性能的角度来看,页面填色机制让虚拟内存有了和物理内存一样的确定性。这样一来,在编写程序的时候就会有这样假设,下层硬件高速缓存的特性对于它们的虚拟地址空间来说,表现出了和程序直接运行在物理地址空间内时一样的特性。

    简单说,页面填色减少了物理页冲突,也即多个虚拟地址通知映射到相同物理页的几率。当上述情况发生时,会频繁地发生缓存不命中从而产生缺页。

 

 

13. 主存链表

内核将主存分成了 5 个链表:

  1.  
    1. 固定 (wired) 页面链表:固定页面被锁定在内存中,不能被调出。

    2. 活动 (active) 页面链表:活动页面是正在被一个或者多个虚拟内存区域使用的页面。

    3. 非活动 (inactive) 页面链表:非活动页面里的内容仍然是已知的内容,但是它们通常不是任何活动区域的一部分。如果页面的内容变“脏”,那么在重新使用该页面之前,必须先将变“脏”的内容写入后备存储中去。一旦页面已经被清理过了,就会把它转移到缓存链表去。

    4. 缓存 (cache) 页面链表:缓存页面里的内容依然是已知的内容,但是它们通常不是任何活动区域的一部分。如果它们被映射到了一个活动的区域,那么必须将它们标为只读,于是对它们执行任何写操作都会使得它们被移除缓存链表。

    5. 空闲 (free) 页面链表:空闲页面里面不含有用的内容,它们将用来满足新发生的缺页请求的需要。 Idle 进程保持空闲链表中 75% 的页面都清零,这样在用它们来解决匿名区域缺页问题时,就不必再清零了。

    主存中可以由用户进程使用的页面是活动,非活动,缓存以及空闲链表中的页面。如果空闲链表中有页面的话,新申请的页面首先从空闲链表中取得,否则就从缓存链表中取。缓存和空闲链表又按颜色细分成了几个独立的链表。

 

 

14.pageout 进程

    页面的替换操作由 pageout 守护进程 (pid 2) 来完成。其目标就是保持非活动,缓存和空闲链表中的页面数量处于希望的范围内。

/*

* Vm_pageout_scan does the dirty work for the pageout daemon.

*/

void vm_pageout_scan(void)

{

[A] page_shortage = free_target + cache_minimum -

(free_count + cache_count);

max_writes_in_progress = 32;

[B] for (page = FIRST(inactive list); page; page = next) {

next = NEXT(page);

if (page_shortage < 0)

break;

if (page busy)

continue;

[C] if (page's object has ref_count > 0 &&

page is referenced)

update page active count;

move page to end of active list;

continue;

}

if (page is invalid)

move page to front of free list;

page shortage--;

continue;

}

[D] if (first time page seen dirty) {

mark page as seen dirty;

move to end of inactive list;

continue;

}

check for cluster of dirty pages around page;

start asynchronous write of page cluster;

move to end of inactive list;

page_shortage--;

max_writes_in_progress--;

if (max_writes_in_progress == 0)

break;

}

[E] page_shortage = free_target + cache_minimum + inactive_target

- (free_count + cache_count + inactive_count);

[F] for (page = FIRST(active list); page; page = next) {

next = NEXT(page);

if (page_shortage < 0)

break;

if (page busy)

continue;

if (page's object has ref_count > 0) {

update page active count;

move page to end of active list;

continue;

}

[G] decrement page active count;

if (page active count > 0) {

move page to end of active list;

continue;

[G] decrement page active count;

if (page active count > 0) {

move page to end of active list;

continue;

}

page_shortage--;

if (page is clean)

move page to end of cache list;

else

move page to end of inactive list;

}

[H] page_shortage = free_minimum - free_count;

for (page = FIRST(cache list); page; page = next) {

next = NEXT(page);

if (page_shortage < 0)

break;

if (page busy)

continue;

move page to front of free list;

}

[I] if (targets not met)

request swap-out daemon to run;

[J] if (nearly all memory and swap in use)

kill biggest process;

}

 

 

15. 采用交换机制的原因

    1> 系统内存太少以至于对进程采用调页机制不能够快的释放内存来满足需求。

    2> 进程处于完全非活动状态操作 10 秒钟。另外,这样的进程会保留一些同用户结构和线程栈相关的内存页面。

分享到:
评论

相关推荐

    FreeBSD 6.0架设管理与应用 pdf

    通过这本书的学习,读者不仅可以掌握FreeBSD 6.0的基本操作,还能深入了解系统管理的高级技巧,为成为熟练的FreeBSD系统管理员打下坚实基础。同时,由于FreeBSD的核心原理和很多工具在后续版本中依然适用,因此书中...

    初级Freebsd命令学习

    初级Freebsd命令学习和使用方法让菜鸟们更加了解Freebsd命令.

    FreeBSD学习笔记整理

    ### FreeBSD学习笔记整理 #### 一、系统基本信息查询 **1. 查看CPU信息** - 使用`sysctl hw.model hw.ncpu`命令可以查看到CPU的型号和核心数量。 - `dmesg | grep "CPU:"`命令也可以用来获取CPU的相关信息。 **2...

    FreeBSD完全学习

    《FreeBSD完全学习》一书提供了详尽的指南,涵盖了FreeBSD操作系统的各个方面,包括安装、配置、开发等,旨在帮助读者全面掌握FreeBSD的使用与管理。以下是从标题、描述、标签及部分内容中提取的关键知识点: ### 1...

    freebSD学习手册 关于学习freebSD的应用

    学习FreeBSD不仅能够帮助用户掌握一个强大的操作系统,还能深入了解计算机网络、系统管理、安全机制等核心IT技能。 ### 关键知识点 #### 1. FreeBSD的历史与发展 FreeBSD起源于加州大学伯克利分校的Berkeley ...

    webmin(freebsd管理)

    freebsd管理工具,直接解压到freebsd中即可……非常好用的管理软件

    FreeBSD6.0架设管理与应用(王俊斌主编)

    对于初学者而言,学习新的操作系统一定会遇到很多问题。但当这些困难获得解决时,就是一次新的成长。因此,当读者在使用 FreeBSD 遇到问题时,千万不因气馁,只要再加把劲,您也可以在 FreeBSD 世界中得心应手...

    freebsd学习资料

    freebsd学习资料大全连载,包括安装配置

    freeBSD架设管理与应用

    FreeBSD是一种基于Unix的开源操作系统,以其稳定性和高效性能在IT行业中受到许多系统管理员和开发者的青睐。本篇文章将深入探讨FreeBSD的架设、管理及其在实际应用中的各种技巧和策略。 一、FreeBSD安装与系统配置 ...

    freebsd.tar.gz_BSD_FreeBSD内核源码_freebsd source_freebsd.tar_linux

    虽然这个压缩包的标题中提到了`linux`,但请注意,FreeBSD和Linux在内核设计上有许多不同之处。Linux采用微内核架构,而FreeBSD采用单内核设计。此外,它们的许可证也不同,Linux遵循GPL,而FreeBSD遵循BSD许可证。...

    FreeBSD中文手册.pdf

    这份"FreeBSD中文手册"是针对FreeBSD系统用户和管理员的一份详细参考资料,旨在帮助读者理解和掌握FreeBSD的操作、安装和日常管理。 手册覆盖了多个关键主题,包括: 1. **安装过程**:介绍了如何在各种硬件平台上...

    FreeBSD 5.x 架设管理与应用

    5、使用者管理 6、網路設定 7、/etc 目錄下的檔案介紹 8、系統調校 9、軟體安裝 10、X Window 的使用 11、網頁伺服器 12、郵件伺服器 13、DNS 伺服器 14、NAT 及防火牆 15、Proxy Server 16、資料庫系統 ...

    FreeBSD学习资料.rar

    压缩文件里包含了:FreeBSD技术内幕.pdf,FreeBSD命令.doc,FreeBSD使用手册.pdf,FreeBSD系统结构手册.pdf,FreeBSD-Porter手册.pdf,解压文件\FreeBSD开发手册.url

    FreeBSD 8.4安装指南

    本指南将详细阐述FreeBSD 8.4的安装过程,以及如何在安装完成后部署Panabit网络管理软件。 一、FreeBSD 8.4安装步骤 1. 获取安装媒介:首先,你需要下载或制作FreeBSD 8.4的安装媒介,通常可以是ISO镜像文件,然后...

    FreeBSD Rsync同步学习与配置全过程

    FreeBSD上的Rsync同步学习与配置是一个重要的话题,特别是对于那些需要高效、可靠地备份和同步数据的系统管理员而言。Rsync是一款强大的文件同步工具,最初设计用来替代rcp,由rsync.samba.org维护。它以其独特的...

    freeBSD架构中文手册

    这份“freeBSD架构中文手册”是针对FreeBSD系统架构的详细指南,适合初学者和有经验的系统管理员使用。手册共200多页,深入浅出地介绍了FreeBSD的核心组件、系统管理以及优化策略。 1. **FreeBSD简介** - FreeBSD...

    FREEBSD学习手册

    根据提供的信息,我们可以总结并详细解释FreeBSD学习手册中的关键知识点。...通过学习这本手册,读者将能够了解FreeBSD的基本概念,掌握安装步骤,并学会如何对其进行配置和管理,从而更好地利用这一强大的操作系统。

    FREEBSD操作系统设计与实现.pdf

    全书共5部分14章。第一部分包括前3章,是对FreeBSD历史、设计和内核服务的综述性介绍...本书适合FreeBSD操作系统技术支持人员、应用程序开发人员、系统管理员和系统程序员阅读,也可供对学习FreeBSD感兴趣的读者参考。

    FreeBSD 6.0 架设管理与应用

    FreeBSD 6.0 架设管理与应用,一本可遇不可求的好书。

Global site tag (gtag.js) - Google Analytics