2007年4月17日星期二

内存管理--基本概念

1.1.1. 物理内存
说白了,物理内存就是计算机内存条的容量。CPU所需要的信息都是从物理内存获得。物理内存被分成大小相等的部分,称为页,其大小为4KB,这些物理页可分为4类:
(1)用于核心自身的code data bss 和stack、,这部分页不能被转移到硬盘上;
(2)执行程序代码,例如/bin/bash和 /lib/libdl-2.3.2.so;他们在物理内存是只读的;
(3)dirty页, 可能被修改了但还没写回硬盘;
(4)anonymous页:这些页不对应硬盘的任何文件,通常是执行程序运行过程中产生的一些变量;例如malloc所分配的空间就是这一类型的页;这些页可以被转移到交换区,如果交换区不存在,那么这些页将一直保留到被删除。
对系统里的每个处理器来说,不同的内存区域可能有不同的存取时间(一般是由内存和处理器的距离决定)。对于同一个内存区域,CPU访问速度一样。Linux2.6核心支持Numa(None Uniformed Memory Access)这种体系结构,NUMA中访问速度相同的一个内存区域称为一个Node,支持这种结构的主要任务就是要尽量减少Node之间的通信,使得每个处理器要用到的数据尽可能放在对它来说最快的Node中。每个Node里的物理内存再分成3个区域: DMA, Normal, HighMem。这样分开之后,物理内存能够被有效地使用,而不至于出现把DMA可用的内存大量给无关的用户进程使用导致驱动程序没法得到足够的DMA内存等情况。此外,每个区都独立地监控本区内存的使用情况,分配时系统会判断从哪个区分配比较合理,综合考虑用户的要求和系统现状。内核的cache由一个或多个slab组成,每个slab包含一个或多个对象。这些对象可能是活跃(正在使用)的,也可能是不活跃的(没有使用)。

1.1.2. 高端和低端物理内存
当系统有32位CPU并且物理内存1GB以上时,Linux必须将物理内存分为高端(high memory)和低端(low memory)来管理。内核不能直接访问高端物理内存,高端物理内存必须先被映像到低端物理内存。860MB以上的物理内存就称为高端物理内存,用于用户空间的程序和页高速缓存;任何可运行与高端内存的东西都可在低端内存运行,slab分配的内存都是低端内存。对于64位CPU就不分高低端内存。
/
1.1.3. Slab 分配器
单单分配页面的分配器肯定是不能满足要求的。内核中大量使用各种数据结构,大小从几个字节到几十上百k不等,都取整到2的幂次个页面那是完全不现实的。2.0的内核的解决方法是提供大小为2,4,8,16,...,131056字节的内存区域。需要新的内存区域时,内核从伙伴系统申请页面,把它们划分成一个个区域,取一个来满足需求;如果某个页面中的内存区域都释放了,页面就交回到伙伴系统。这样做的效率不高。有许多地方可以改进:
slab分配器负责处理来至核心模块的小于1个物理页的空间的请求。slab分配器把小物理空间看成对象,当这些对象(空间)不使用时,并不马上删除,而是存储在slab cache中。同一类型的这样的请求形成一个cache,slab将同一类型的请求尽可能放在一个物理页上。当slab 无法满足物理页请求时,slab就向Buddy分配器请求空间。Slab分配器只能分配DMA和NORMAL 区域中的物理空间。

1.1.4. 虚拟内存和swap
无穷大的快速的内存是每个使用操作系统的人所希望的。然而,这似乎是不可能的,至少目前的技术水平,况且,无穷大与快速本身就可能矛盾。为了解决无穷大,linux引入了虚拟存储系统。虚拟内存是计算机将一部分硬盘空间划作“内存”来使用。当内存的需求超出了系统中的物理内存量,那么 Linux 可以使用磁盘空间作为 RAM 的虚拟扩展,即(swap space)。Linux能够使用文件系统中的一个常规文件或一个独立的分区作为交换空间。交换分区要快一些,只好交换分区不与目录结构打交道。
当可用的物理内存空间小于一个值(可以通过proc/sys/vm来设置)时,就发生缺页操作,内核会将暂时不用的物理内存页的内容移到交换空间上,这样一来,这块内存就可用于其它目的。当需要用到原始的内容时,它们被重新读入内存。从物理内存移到SWAP DISK的特殊磁盘段上叫做虚拟内存的页导出(page out);反之,叫做页导入(page in)。
Linux下运行的程序只是看到有大量的内存可供使用而并没有注意到有时它们的一部分是驻留在硬盘上的科学,这时程序就不会象一直在物理内存中运行的那样快,因为读写硬盘要比直接使用物理内存慢得多(要慢数千倍)。
当系统的不活跃物理内存(inactive memory)很大,而已经被使用的交换区的空间也很大,这是可能,这样的数据并不能表明系统性能不好,这现象发生的发生,可能是某个应用程序需要大量空间,从而把许多处于睡眠的守护进程放如交换区,当该应用程序停止运行时,大量的物理内存被释放,这时候没有必要把这些守护进程拷入物理内存,因为尽可能利用物理内存是为了减少CPU等待数据的时间从而加快响应时间,拷入不但消耗CPU时间,而且盲目拷入,可能由于没有使用就又被转储回交换空间。
下面几种情况都会增大进程的虚拟内存空间:
加载程序映像。例如 ls 命令。这个命令,象所有的执行映像一样,由执行代码和数据组成。映像文件中包括将执行代码和相关的程序数据以及加载到进程地虚拟内存中所需要的所有信息。
进程可以在运行过程中申请额外的(虚拟)内存,比如用于存放它读入的文件的内容。新分配的虚拟内存需要连接到进程现存的虚拟内存中才能使用。
Linux 进程使用通用代码组成的共享库,例如文件处理。每一个进程都包括库的一份拷贝没有意义, Linux 使用共享库,几个同时运行的进程可以共享。这些共享库里边的代码和数据必须连接到该进程的虚拟地址空间和其它共享该库的进程的虚拟地址空间。

通常发生缺页时,系统首先在交换空间中找,如果找到,则被换入内存;当系统没有足够的物理内存时候,这些页又将被交换出来(到其它的交换空间中)。如果没有足够的虚拟内存来容纳所有这些页面,Linux就会波动而不正常;但经过一段较长的时间Linux会恢复,但此时系统已不可用了。在移去一个交换空间之前,你应该检查(例如,用free)是否有足够的空闲内存。

1.1.5. 高速缓存

物理内存是一种有限而又不充足的资源,高速缓存不可能做的很大(它不可能包容要用到的所有数据)。当缓存充满了数据时,其中最长时间不用的数据将被舍弃以腾出内存空间用于新的数据。高速缓存的大小会制约CPU的执行效率,虽然CPU主频很快,但它取不到数据,则只有空运行。因此,高速缓存的大小很重要。缓冲的效力主要是由它的大小决定的。缓冲大小太小的话等于没用:它只能容纳一点数据,因此在被重用时,所有缓冲的数据都将被倾空。实际的大小依赖于数据读写的频次、相同数据被访问的频率。只有用实验的方法才能知道。如果缓存有固定的大小,那么缓存太大了也不好,因为这会使得空闲的内存太小而导致进行交换操作(这同样是慢的)。为了最有效地使用实际内存,Linux自动地使用所有空闲的内存作为高速缓冲,即缓存的大小可以随可用内存动态变化,但也可以通过修改内核参数而改成固定的大小当程序需要更多的内存时。
高速缓存分三大类:hardware cache,memory cache and disk cache。Memory cache 和disk cache又被成为kernel cache, 其空间都可以被回收。无论是memory cache还是disk cache只会不断地吃物理内存,而不会主动释放。Linux内核利用 回收(reclaim)算法(PERA)来增加可用物理页的页数目。

(1)memory cache
通常由“buddy system”负责每个区域的物理内存的分配。为了提高性能,在物理内存划出一块缓存区,用于分配给只需一个物理页的请求。对于每个CPU的每个区域(DMA,normal memory, high memory)都有一个这类cache。这个缓存区又分成两类:hot cache 和 cold cache。hot cache 存储了那些可能还在CPU 硬件 cache中的数据。这部分cache 是memory cache。此外memory cache还包括slab allocator cache。
(2)disk cache
disk cache包括dentry cache、inode cache和page cache。这里我们只讨论page cache,为方便,该小节下面讲到高速缓存就是指page cache。
与访问物理内存相比,磁盘的读写速度很慢,可是在较短的时间内多次读/写磁盘的同一部分也是常有的事。为了缓解两类存储器速度的不匹配,Linux内存管理提供了逻辑上属于外存储管理系统而实际是占用物理内存空间的高速缓存。除非对所要访问的文件置位:O_DIRECT,否则对该文件读或写都必须经过page cache。使用page_cache时,每从硬盘读一个页或写一个页到硬盘时,首先检查page cache 是否有该页,如果没有,则在page cache 加入一个entry并将该页数据拷入page cache,然后读入用户空间或留日后写如硬盘。只要有足够的物理内存,page cache里内容将永远保存在那里知道系统重启或物理页面回收(reclaim)。对于要写入硬盘的数据,先保存在page cache,过一段时间再写入硬盘。由于不同的访问方式,磁盘上的同一数据可能在page cache 有多份拷贝,每份用不同的address_space结构来表示。Page cache 可分为用于存取磁盘文件、磁盘块数据和交换高速缓存(swap cache)。
交换高速缓存是指这样一部分物理内存空间,其装载的数据曾经存储在交换分区,在被导入物理内存后,交换分区目前还保留这些数据。只要这些页面在导入交换分区后没有被修改,则下次此页面被导出物理内存时,就不必再进行写操作,这些页面都可以简单的丢弃。在交换频繁发生的系统中,Swap Cache可以省下很多不必要且耗时的磁盘操作。优点可以从两方面讲:当某个进程需要这些数据时,因为已经在物理内存,因此没有缺页操作;但交换高速缓存需要给其它进程使用时,如果这些数据没有被改变,就不需要转储到交换区的操作,这就减少了I/O操作。

Page Cache 用来加速硬盘上可执行映象文件与数据文件的存取。它每次缓冲一个页面的文件内容。页面从磁盘上读入内存后缓存在page cache中。page cache缓冲文件的一页内容, buffer cache缓冲磁盘块内容,page cache写回时会使用临时的buffer cache来写磁盘。Buffer Cache的单元的大小一般固定(例如说512字节)并且包含从块设备读出或者写入的信息块。块设备是仅能够以固定大小块进行读写操作的设备。利用设备标志符和所需块号作索引可以在buffer cache中迅速地找到数据。块设备只能够通过buffer cache来存取。如果数据在buffer cache中可以找到则无需从物理块设备(如硬盘)中读取,这样可以加速访问。

1.1.6. 缺页(page fault
当CPU所需要的指令或数据不在物理内存时,就会产生缺页中断。当该中断是从设备(如硬盘)子系统包括交换区获取指令或数据时,我们称之为主缺页(major paging)中断。主缺页中断导致延时。对于正在一个系统中运行的任务,我们把其所占有的那部分物理内存称之为该任务的工作集(work set)。当CPU所需要的指令或数据不在对应的工作集,即在相应的任务的页表中没有该物理页的映像(mapped pages),但已经存在于物理内存,即可以在物理内存的其它地址上找到,但还未建立物理内存与虚拟地址空间转换关系,这时所产生缺页中断称之为次缺页(minor paging)中断。例如系统种的共享库,就属于这种情形,实际上多个进程只是共享 同一共享库的物理内存页,第一个引用共享库的进程导致一个主缺页,而之后的其它进程引用则只是次缺页,在给相应的工作集上建立到该库的物理内存页的连接。

1.1.7. 物理页的状态
(1)闲置(FREE):闲置的物理页可以立即用于分配。
(2)活动(ACTIVE):活跃物理内存指正在被内核或用户进程使用的物理内存。
(3)不活跃物理内存(inactive): 不活跃物理内存可分为:(i)“dirty” 页,(ii)“clean”页,(iii)“laundry”页。当物理内存不够使用(即闲置的物理页数无法满足进程的请求)时,首先是不活跃物理内存将被转储到硬盘上,然后从不活跃物理内存回收可用于分配的物理内存页。不活跃物理内存包括页高速缓存,缓冲区高速缓存,交换高速缓存中的部分空间。当不活跃物理内存页较少时,说明物理内存的短缺。


1.1.8. 回收物理内存

可回收的物理内存分为:
(1) 用户态地址空间的匿名物理页
(2) tmpfs文件系统已经映射的页
(3) 用户态地址空间中已经映射的物理页
(4) kernel cache
映射的物理页指该物理页已经映射到某一文件的一部分。匿名物理页指那些起内容不需要在外部设备上存储的物理页。
回收的方式:
(1) 触发式回收:系统在处理物理内存分配请求时失败。
(2) 定期回收

没有评论: