极限首页 业界焦点 软件工程师之路 系统工程师之路 网络工程师之路 软件下载 技术社区
 bash编程学习笔记(一)
 RPM 打包技术与典型 SPEC
 Linux Kernel核心中文手册
 Linux Kernel核心中文手册
 精通递归程序设计
 Linux Kernel核心中文手册
 Linux/Unix环境下的make命
 Linux Kernel核心中文手册
 bash编程学习笔记(二)
 Linux操作系统内核编译详解
 bash编程学习笔记(一)
 RPM 打包技术与典型 SPEC
 Linux Kernel核心中文手册
 Linux Kernel核心中文手册
 精通递归程序设计
 Linux Kernel核心中文手册
 Linux/Unix环境下的make命
 Linux Kernel核心中文手册
 bash编程学习笔记(二)
 Linux操作系统内核编译详解

Shell 中文手册

Python 2.3 中文手册

Python 2.4 中文手册

Mysql 4.x 中文手册

PHP 4.x 中文手册

Apache 2.x 中文手册
更多手册

站内搜索:
当前位置:首页>>软件工程师之路>>编程进阶>>正文
Linux Kernel核心中文手册(3、4)(2)
时间:2005-11-08 作者:未知 来源:未知

   

减少buffer cache 和page cache的大小

将系统V的共享内存页交换出去

交换和废弃页

 

如果系统中的空闲页数低于free_pages_low,核心交换进程将试图在下一次运行前释放6页。否则试图释放3页。以上的每一种方法都要被尝 试直到释放了足够的页。核心交换进程记录了它上一次使用的释放物理页的方法。每一次运行时它都会首先尝试上一次成功的方法来释放页。  

释放了足够的页之后,交换进程又一次睡眠,直到它的计时器又一次过期。如果核心交换进程释放页的原因是系统空闲页的数量少于free_pages_low,它只睡眠平时的一半时间。只要空闲页数大于free_pages_low,交换进程就恢复原来的时间间隔进行检查。

 

3.8.1 Reducing the size of the Page and Buffer Caches

 

page 和buffer cache中的页是释放到free_area向量中的好选择。Page Cache,包含了内存映射文件的页,可能有不必要的数据,占去了系统的内存。同样,Buffer Cache ,包括了从物理设备读或向物理设备写的数据,也可能包含了无用的缓冲。当系统中的物理页将要耗尽的时候,废弃这些缓存区中的页相对比较容易,因为它不需要 向物理设备写(不象将页从内存中交换出去)。废弃这些页不会产生多少有害的副作用,只不过使访问物理设备和内存映射文件时慢一点。虽然如此,如果公平地废 弃这些缓存区中的页,所有的进程受到的影响就是平等的。

 

每一次当核心交换进程要缩小这些缓存区时,它要检查mem_map页矢量中的页块,看是否可以从物理内存中废弃。如果系统空闲页太低(比较危险时) 而核心交换进程交换比较厉害,这个检查的页块大小就会更大一些。页块的大小进行循环检查:每一次试图减少内存映射时都用一个不同的页块大小。这叫做 clock算法,就象钟的时针。整个mem_map页向量都被检查,每次一些页。

参见mm/filemap.c shrink_map()

 

检查的每一页都要判断缓存在page cache 或者buffer cache中。注意共享页的废弃这时不考虑,一页不会同时在两个缓存中。如果该页不在这两个缓冲区中,则mem_map页向量表的下一页被检查。

缓存在buffer cache ch中的页(或者说页中的缓冲区被缓存)使缓冲区的分配和释放更有效。缩小内存映射的代码试图释放包含检查过的页的缓冲区。如果缓冲区释放 了,则包含缓冲区的页也被释放了。如果检查的页是在Linux的page cache 中,它将从page cache 中删除并释放。

参见 fs/buffer.c free_buffer()

 

如果这次尝试释放了足够的页,核心交换进程就会继续等待直到下一次被周期性地唤醒。因为释放的页不属于任何进程的虚拟内存(只是缓存的页),因此不需要更新进程的页表。如果废弃的缓存页仍然不够,交换进程会试图交换出一些共享页。

 

3.8.2 Swapping Out System V Shared Memory Pages(交换出系统V的共享内存页)

 

系统V的共享内存是一种进程间通讯的机制,通过两个或多个进程共享虚拟内存交换信息。进程间如何共享内存在第5章详细讨论。现在只要讲讲每一块系统 V共享内存都用一个shmid_ds的数据结构描述就足够了。它包括一个指向vm_area_struct链表数据结构的指针,用于共享此内存的每一个进 程。Vm_area_struct数据结构描述了此共享内存在每一个进程中的位置。这个系统V的内存中的每一个vm_area_struct结构都用 vm_next_shared和vm_prev_shared指针连接在一起。每一个shmid_ds数据结构都有一个页表条目的链表,每一个条目都描述 一个共享的虚拟页和物理页的对应关系。

 

核心交换进程将系统V的共享内存页交换出去时也用clock算法。它每一次运行都记录了上一次交换出去了那一块共享内存的那一页。它用两个索引来记 录:第一个是shmid_ds数据结构数组中的索引,第二个是这块共享内存区的页表链中的索引。这样可以共享内存区的牺牲比较公平。

参见ipc/shm.c shm_swap()

 

因为一个指定的系统V共享内存的虚拟页对应的物理页号包含在每一个共享这块虚拟内存的进程的页表中,所以核心交换进程必须修改所有的进程的页表来体 现此页已经不在内存而在交换文件中。对于每一个交换出去的共享页,交换进程必须找到在每一个共享进程的页表中对应的此页的条目(通过查找每一个 vm_area_struct指针)如果在一个进程页表中此共享内存页的条目有效,交换进程要把它变为无效,并且标记是交换页,同时将此共享页的在用数减 1。交换出去的系统V共享页表的格式包括一个在shmid_ds数据结构组中的索引和在此共享内存区中页表条目的索引。

 

如果所有共享的内存都修改过,页的在用数变为0,这个共享页就可以写到交换文件中。这个系统V共享内存区的shmid_ds数据结构指向的页表中此 页的条目将会换成交换出的页表条目。交换出的页表条目无效但是包含一个指向打开的交换文件的索引和此页在此文件内的偏移量。这个信息用于将此页再取回物理 内存中。  

3.3 Swapping Out and Discarding Pages

 

交换进程轮流检查系统中的每一个进程是否可以用于交换。好的候选是可以交换的进程(有一些不行)并且有可以从内存中交换出去或废弃的一个或多个页。只有其他方法都不行的时候才会把页从物理内存交换到系统交换文件中。

参见 mm/vmscan.c swap_out()

 

来自于映像文件的执行映像的大部分内容可以从文件中重新读出来。例如:一个映像的执行指令不会被自身改变,所以不需要写到交换文件中。这些页只是被简单地废弃。如果再次被进程引用,可以从执行映像再次加载到内存中。  

一旦要交换的进程确定下来,交换进程就查看它的所有虚拟内存区域,寻找没有共享或锁定的区域。Linux不会把选定进程的所有可以交换出去的页都交换出去,而只是去掉少量的页。如果页在内存中锁定,则不能被交换或废弃。

参见mm/vmscan.c swap_out_vme() 跟踪进程mm_struct中排列的vm_area_struct结构中的vm_next vm_nex指针。

 

Linux的交换算法使用了页的年龄。每一个页都有一个计数器(放在mem_map_t数据结构中),告诉核心交换进程此页是否值得交换出去。页不 用时变老,访问时更新。交换进程只交换老的页。缺省地,页第一次分配时年龄赋值为3。每一次访问,它的年龄就增加3,直到20。每一次系统交换进程运行时 它将页的年龄减1使页变老。这个缺省的行为可以更改,所以这些信息(和其他相关信息)都存放在swap_control数据结构中。

如果页太老(年龄age = 0),交换进程会进一步处理。脏页可以交换出去,Linux在描述此页的PTE中用一个和体系结构相关的位来描述这种页(见图3.2)。但是,并非所有的 脏页都需要写到交换文件。每一个进程的虚拟内存区域都可以拥有自己的交换操作(由vm_area_struct中的vm_ops指针指示),如果这样,交 换进程会用它的这种方式。否则,交换进程会从交换文件中分配一页,并把此页写到该文件中。

 

此页的页表条目会用一个无效的条目替换,但是包括了此页在交换文件的信息:此页所在文件内的偏移和所用的交换文件。不管什么方式交换,原来的物理页被放回到free_area重释放。干净(或不脏)的页可以被废弃,放回到free_area中重用。

 

如果交换或废弃了足够的可交换进程的页,交换进程重新睡眠。下一次唤醒时它会考虑系统中的下一个进程。这样,交换进程轻咬去每一个进程的物理页,直到系统重新达到平衡。这种做法比交换出整个进程更公平。

 

3.9 The Swap Cache(交换缓存)

 

当把页交换到交换文件时,Linux会避免写不必要写的页。有时可能一个页同时存在于交换文件和物理内存中。这发生于一页被交换出内存然后在进程要访问时又被调入内存的情况下。只要内存中的页没有被写过,交换文件中的拷贝就继续有效。

 

Linux用swap cache来记录这些页。交换缓存是一个页表条目或者系统物理页的链表。一个交换页有一个页表条目,描述使用的交换文件和它在交换文件中的位置。如果交换 缓存条目非0,表示在交换文件中的一页没有被改动。如果此页后来被改动了(被写),它的条目就从交换缓存中删除) 当Linux需要交换一个物理页到交换文件的时候,它查看交换缓存,如果有此页的有效条目,它不需要把此页写到交换文件。因为内存中的此页从上次读到交换 文件之后没有被修改过。

 

交换缓存中的条目是曾经交换出去的页表条目。它们被标记为无效,但是包含了允许Linux找到正确交换文件和交换文件中正确页的信息。

 

3.10 Swapping Page In(交换进)

 

保存在交换文件中的脏页可能又需要访问。例如:当应用程序要向虚拟内存中写数据,而此页对应的物理页交换到了交换文件时。访问不在物理内存的虚拟内 存页会引发page fault。Page fault是处理器通知操作系统它不能将虚拟内存转换到物理内存的信号。因为交换出去后虚拟内存中描述此页的页表条目被标记为无效。处理器无法处理虚拟地 址到物理地址的转换,将控制转回到操作系统,告诉它发生错误的虚拟地址和错误的原因。这个信息的格式和处理器如何把控制转回到操作系统是和处理器类型相关 的。处理器相关的page faule处理代码必须定位描述包括出错虚拟地址的虚拟内存区的vm_area_struct的数据结构。它通过查找该进程的 vm_area_struct数据结构,直到找到包含了出错的虚拟地址的那一个。这是对时间要求非常严格的代码,所以一个进程的 vm_area_struct数据结构按照特定的方式排列,使这种查找花费时间尽量少。

参见 arch/i386/mm/fault.c do_page_fault()

 

执行了合适的和处理器相关的动作并找到了包括错误(发生)的虚拟地址的有效的虚拟内存,page fault的处理过程又成为通用的,并可用于Linux能运行的所有处理器。通用的page fault处理代码查找错误虚拟地址的页表条目。如果它找到的页表条目是交换出去的页,Linux必须把此页交换回物理内存。交换出去的页的页表条目的格 式和处理器相关,但是所有的处理器都将这些页标为无效并在页表条目中放进了在交换文件中定位页的必要信息。Linux使用这种信息把此页调回到物理内存 中。

参见mm/memory.c do_no_page()

 

这时,Linux知道了错误(发生)的虚拟地址和关于此页交换到哪里去的页表条目。Vm_area_struct数据结构可能包括一个例程的指针, 用于把这块虚拟内存中的页交换回到物理内存中。这是swapin操作。如果这块内存中有swapin操作,Linux会使用它。其实,交换出去的系统V的 共享内存之所以需要特殊的处理因为交换的系统V的共享内存页的格式和普通交换页的不同。如果没有swapin操作,Linux假定这是一个普通页,不需要 特殊的处理。它分配一块空闲的物理页并将交换出去的页从交换文件中读进来。关于从交换文件哪里(和哪一个交换文件)的信息取自无效的页表条目。 参见mm/page_alloc.c swap_in()

 

如果引起page fault的访问不是写访问,页就留在交换缓存中,它的页表条目标记为不可写。如果后来此页又被写,会产生另一个page fault,这时,此页被标志为脏页,而它的条目也从交换缓存中删除。如果此页没有被修改而又需要交换出来,Linux就可以避免将此页写到交换文件,因 为此页已经在交换文件中了。

 

如果将此页从交换文件调回的访问是写访问,这个页就从交换缓存中删除,此页的页表条目页标记为脏页和可写。  

 

Chapter 4

 

Processes (进程)

本章描述进程是什么以及Linux如何创建、管理和删除系统中的进程。

 

进程执行操作系统中的任务。程序是存放在磁盘上的包括一系列机器代码指令和数据的可执行的映像,因此,是一个被动的实体。进程可以看作是一个执行中 的计算机程序。它是动态的实体,在处理器执行机器代码指令时不断改变。处理程序的指令和数据,进程也包括程序计数器和其他CPU的寄存器以及包括临时数据 (例如例程参数、返回地址和保存的变量)的堆栈。当前执行的程序,或者说进程,包括微处理器中所有的当前的活动。Linux是一个多进程的操作系统。进程 是分离的任务,拥有各自的权利和责任。如果一个进程崩溃,它不应该让系统中的另一个进程崩溃。每一个独立的进程运行在自己的虚拟地址空间,除了通过安全的 核心管理的机制之外无法影响其他的进程。

 

在一个进程的生命周期中它会使用许多系统资源。它会用系统的CPU执行它的指令,用系统的物理内存来存储它和它的数据。它会打开和使用文件系统中的 文件,会直接或者间接使用系统的物理设备。Linux必须跟踪进程本身和它使用的系统资源以便管理公平地管理该进程和系统中的其他进程。如果一个进程独占 了系统的大部分物理内存和CPU,对于其他进程就是不公平的。

 

系统中最宝贵的资源就是CPU。通常系统只有一个。Linux是一个多进程的操作系统。它的目标是让进程一直在系统的每一个CPU上运行,充分利用 CPU。如果进程数多于CPU(多数是这样),其余的进程必须等到CPU被释放才能运行。多进程是一个简单的思想:一个进程一直运行,直到它必须等待,通 常是等待一些系统资源,等拥有了资源,它才可以继续运行。在一个单进程的系统,比如DOS,CPU被简单地设为空闲,这样等待的时间就会被浪费。在一个多 进程的系统中,同一时刻许多进程在内存中。当一个进程必须等待时操作系统将CPU从这个进程拿走,并将它交给另一个更需要的进程。是调度程序选择了

下一次最合适的进程。Linux使用了一系列的调度方案来保证公平。

 

Linux支持许多不同的可执行文件格式,ELF是其中之一,Java是另一个。Linux必须透明地管理这些文件,因为进程使用系统的共享的库。

 

4.1 Linux Processes(Linux的进程)

 

Linux中,每一个进程用一个task_struct(在Linux中task和process互用)的数据结构来表示,用来管理系统中的进程。 Task向量表是指向系统中每一个task_struct数据结构的指针的数组。这意味着系统中最大进程数受task向量表的限制,缺省是512。当新的 进程创建的时候,从系统内存中分配一个新的task_struct,并增加到task向量表中。为了更容易查找,用current指针指向当前运行的进 程。

参见include/linux/sched.h

 

除了普通进程,Linux也支持实时进程。这些进程必须对于外界事件迅速反应(因此叫做“实时”),调度程序必须和普通用户进程区分对待。虽然task_struct数据结构十分巨大、复杂,但是它的域可以分为以下的功能:

 

State 进程执行时它根据情况改变状态(state)。Linux进程使用以下状态:(这里漏掉了SWAPPING,因为看来没用到)

Running 进程在运行(是系统的当前进程)或者准备运行(等待被安排到系统的一个CPU上)

Waiting 进程在等待一个事件或资源。Linux区分两种类型的等待进程:可中断和不可中断的(interruptible and uninterruptible)。可中断的等待进程可以被信号中断,而不可中断的等待进程直接等待硬件条件,不能被任何情况中断。

Stopped 进程停止了,通常是接收到了一个信号。正在调试的进程可以在停止状态。

Zombie 终止的进程,因为某种原因,在task 向量表重任旧有一个task_struct数据结构的条目。就想听起来一样,是一个死亡的进程。

 

Scheduling Information 调度者需要这个信息用于公平地决定系统中的进程哪一个更应该运行。

Identifiers 系统中的每一个进程都有一个进程标识符。进程标识符不是task向量表中的索引,而只是一个数字。每一个进程也都有用户和组(user and group)的标识符。用来控制进程对于系统中文件和设备的访问。

Inter-Process Communication Linux支持传统的UNIX-IPC机制,即信号,管道和信号灯(semaphores),也支持系统V的IPC机制,即共享内存、信号灯和消息队列。关于Linux支持的IPC机制在第5章中描述。

Links 在Linux系统中,没有一个进程是和其他进程完全无关的。系统中的每一个进程,除了初始的进程之外,都有一个父进程。新进程不是创建的,而是拷贝,或者 说从前一个进程克隆的(cloned)。每一个进程的task_struct中都有指向它的父进程和兄弟进程(拥有相同的父进程的进程)以及它的子进程的 的指针。在Linux系统中你可以用pstree命令看到正在运行的进程的家庭关系。

 

init(1)-+-crond(98)

|-emacs(387)

|-gpm(146)

|-inetd(110)

|-kerneld(18)

|-kflushd(2)

|-klogd(87)

|-kswapd(3)

|-login(160)---bash(192)---emacs(225)

|-lpd(121)

|-mingetty(161)

|-mingetty(162)

|-mingetty(163)

|-mingetty(164)

|-login(403)---bash(404)---pstree(594)

|-sendmail(134)

|-syslogd(78)

`-update(166)

 

另外系统中的所有的进程信息还存放在一个task_struct数据结构的双向链表中,根是init进程。这个表让Linux可以查到系统中的所有的进程。它需要这个表以提供对于ps或者kill等命令的支持。

Times and Timers 在一个进程的生命周期中,核心除了跟踪它使用的CPU时间还记录它的其他时间。每一个时间片(clock tick),核心更新jiffies中当前进程在系统和用户态所花的时间综合。Linux也支持进程指定的时间间隔的计数器。进程可以使用系统调用建立计 时器,在计时器到期的时候发送信号给自己。这种计时器可以是一次性的,也可是周期性的。

File system 进程可以根据需要打开或者关闭文件,进程的task_struct结构存放了每一个打开的文件描述符的指针和指向两个VFS I节点(inode)的指针。每一个VFS I节点唯一描述一个文件系统中的一个文件或目录,也提供了对于底层文件系统的通用接口。Linux下如何支持文件系统在第9章中描述。第一个I节点是该进 程的根(它的主目录),第二个是它的当前或者说pwd目录。Pwd取自Unix命令:印出工作目录。这两个VFS节点本身有计数字段,随着一个或多个进程 引用它们而增长。这就是为什么你不能删除一个进程设为工作目录的目录。

Virtual memory 多数进程都有一些虚拟内存(核心线程和核心守护进程没有),Linux核心必须知道这些虚拟内存是如何映射到系统的物理内存中的。

Processor Specific Context 进程可以看作是系统当前状态的总和。只要进程运行,它就要使用处理器的寄存器、堆栈等等。当一个进程暂停的时候,这些进程的上下文、和CPU相关的上下文 必须保存到进程的task_struct结构中。当调度者重新启动这个进程的时候,它的上下文就从这里恢复。


  共4页: 上一页 [1] 2 [3] [4] 下一页   
推荐】【 】【关闭


关于极限 | 站内地图 | 意见反馈 | 广告服务 | 数据服务 | 联系我们
本站所刊登的文章,技术资料,软件均整理于网络资源或本站原创,转载请务必联系原作者或本站。
Copyright ? 2001-2004 UPLinux.com All Rights Reserved.
本站唯一联系信箱:
京ICP备05010519